How to unit test logging error with Spock framework in groovy
17,187
Solution 1
you could check for an invocation of error on the logger
@Grab(group='org.spockframework', module='spock-core', version='0.7-groovy-2.0')
@Grab(group='org.slf4j', module='slf4j-api', version='1.7.7')
@Grab(group='ch.qos.logback', module='logback-classic', version='1.1.2')
import org.slf4j.Logger
class MockLog extends spock.lang.Specification {
public class Car {
private Logger logger = org.slf4j.LoggerFactory.getLogger(Car.class);
void startCar() {
logger.error('car stopped working');
}
}
def "mock log"() {
given:
def car = new Car()
car.logger = Mock(Logger)
when:
car.startCar()
then:
1 * car.logger.error('car stopped working')
}
}
edit: Full example https://github.com/christoph-frick/spock-test-logging
Solution 2
My Loggers are private static final so I cannot use solution mentioned above and rather not use Reflection.
If you are using Spring, you have acces to OutputCaptureRule.
@Rule
OutputCaptureRule outputCaptureRule = new OutputCaptureRule()
def test(){
outputCaptureRule.getAll().contains("<your test output>")
}
Author by
letter Q
Updated on July 28, 2022Comments
-
letter Q almost 2 years
So I have a class that has a method that logs a message:
class Car { private Logger logger = LoggerFactory.getLogger(Car.class); void startCar() { logger.error("car stopped working"); } }
How can I test that the error was logged using the spock testing framework?
class CarTest extends Specification { def "test startCar"() { given: Car newCar = new Car(); when: newCar.startCar(); then: // HOW CAN I ASSERT THAT THE MESSAGE WAS LOGGED??? } }
-
xetra11 almost 6 years
groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: LOG
. In your example you have access to car.logger - but how to this if the class is not within the Spock Testclass? -
matt freake almost 6 yearsThis example seems misleading. In a real life scenario, your logger would not be acccessible to your test code (class Car would not be inside the Specification)
-
cfrick almost 6 years@mattfreake I added a link to a full example to show, that this does not rely on the class to be inside the test. This was done to have a short example. If you mean something else, please elaborate. If you are against writing tests like this, then I am with you - but please blame OP and not the answer. If you need something so badly logged, that it merits writing a test, then provide a proper infrastructure for it. If the test is hairy or hard to write, it's not the tests fault but the fault of the SUT.
-
L. Dai over 4 yearsHow does your car instance have access to the logger? isn't it private?
-
cfrick over 4 years@L.Dai Groovy and/or Spock don't care. Also private on the jvm is not really private (can at least be accessed via reflection)
-
randy almost 4 yearsNot only does this work with Spring, but it also works with Travis CI. Previously,
OutputCapture
was the class I would use in Spring/Spock, but it was deprecated and would fail the CI build. I'm glad I searched for another answer and found this! Also, I feel I should mention we're using@Slf4j
, and this is perfect. Thanks! -
BeshEater over 2 yearsYou may also need to add dependency
'org.spockframework:spock-junit4:2.0-groovy-3.0'
and also set the parameterfollow="true"
for your Console appender in the log4j2 configuration file (see stackoverflow.com/a/70350184/10592946)