The first year of new graduates is almost over. While using Spock's framework, I stumbled upon various mocking methods of Mockito and Spock, so I made a memorandum & shared it for similar people. It would be better to create an instance in the actual situation without mocking the code described here, but it is just an example ...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// https://mvnrepository.com/artifact/org.spockframework/spock-core
testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
// https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.6', ext: 'pom'
}
It is posted on GitHub.
Mockito
Use when --then Return
to set the value returned by the mock. Since spockComponent1Factory is an injection target, ʻinitMocks is added with
setup and ʻInjectMocks
annotation is added. It seems that you can check the number of times by writing true
in the verify
part, but it feels very strange ...
SpockComponent1FactoryTest.groovy
@InjectMocks
SpockComponent1Factory spockComponent1Factory
@Mock
SpockComponent2Factory spockComponent2Factory
@Mock
SpockComponent2 spockComponent2
@Mock
SpockComponent3 spockComponent3
@Mock
SpockComponent4 spockComponent4
def setup() {
initMocks(this)
}
def "GetValueFromSpockComponent4 -Check the number of calls"() {
given:
when(spockComponent2Factory.create(any(Integer.class))).thenReturn(spockComponent2)
when(spockComponent2.getSpockComponent3()).thenReturn(spockComponent3)
when(spockComponent3.getSpockComponent4()).thenReturn(spockComponent4)
when:
spockComponent1Factory.getValueFromSpockComponent4(0)
then:
verify(spockComponent2Factory, times(1)).create(any(Integer.class)) || true
}
Use RETURN_DEEP_STUBS
to mock nested instances. By rewriting the above test, it can be written as follows.
SpockComponent1FactoryTestAlt.groovy
@InjectMocks
SpockComponent1Factory spockComponent1Factory
@Mock
SpockComponent2Factory spockComponent2Factory
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
SpockComponent2 spockComponent2
@Mock
SpockComponent4 spockComponent4
def setup() {
initMocks(this)
}
def "getValueFromSpockComponent -Call count check break"() {
given:
when(spockComponent2Factory.create(any(Integer.class))).thenReturn(spockComponent2)
when(spockComponent2.getSpockComponent3().getSpockComponent4()).thenReturn(spockComponent4)
when:
spockComponent1Factory.getValueFromSpockComponent4(0)
then:
verify(spockComponent2Factory, times(1)).create(any(Integer.class)) || true
}
Spock
A similar test written in Spock looks like this: If you want to check the number of executions, it seems that the test will not pass unless you mock and stub at the same time in the then
clause. By the way, in Spock, if you want to overwrite the behavior set in setup
with individual test cases, it seems that you need to do it in the then
clause. (Reference: Stackoverflow-Official Document)
SpockComponent1FactoryTestSpock.groovy
SpockComponent1Factory spockComponent1Factory
SpockComponent2Factory spockComponent2Factory
SpockComponent2 spockComponent2
SpockComponent3 spockComponent3
SpockComponent4 spockComponent4
def setup() {
spockComponent2Factory = Mock(SpockComponent2Factory.class)
spockComponent2 = Mock(SpockComponent2.class)
spockComponent3 = Mock(SpockComponent3.class)
spockComponent4 = Mock(SpockComponent4.class)
}
def "GetValueFromSpockComponent4 -Call count check failed"() {
given:
spockComponent3.getSpockComponent4() >> spockComponent4
spockComponent2.getSpockComponent3() >> spockComponent3
spockComponent2Factory.create(_ as Integer) >> spockComponent2
when:
spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
spockComponent1Factory.getValueFromSpockComponent4(0)
then:
1 * spockComponent2Factory.create(_ as Integer)
}
def "GetValueFromSpockComponent4 -Successful call count check"() {
given:
spockComponent3.getSpockComponent4() >> spockComponent4
spockComponent2.getSpockComponent3() >> spockComponent3
when:
spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
spockComponent1Factory.getValueFromSpockComponent4(0)
then:
1 * spockComponent2Factory.create(_ as Integer) >> spockComponent2
}
Spock also needs some ingenuity to mock nested instances. Less than.
SpockComponent1FactoryTestSpockAlt.groovy
SpockComponent1Factory spockComponent1Factory
SpockComponent2Factory spockComponent2Factory
SpockComponent2 spockComponent2
SpockComponent4 spockComponent4
def setup() {
spockComponent2Factory = Mock(SpockComponent2Factory.class)
spockComponent2 = Mock(SpockComponent2.class)
spockComponent4 = Mock(SpockComponent4.class)
}
def "GetValueFromSpockComponent4 -Call count check break"() {
given:
spockComponent2.getSpockComponent3() >> {
Mock(SpockComponent3.class) {
getSpockComponent4() >> spockComponent4
}
}
when:
spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
spockComponent1Factory.getValueFromSpockComponent4(0)
then:
1 * spockComponent2Factory.create(_ as Integer) >> spockComponent2
}
In the implementation code, null is directly put in the method that takes the argument of String.
SpockComponent1Factory.java
public void nullArgumentMethodCall() {
spockComponent2Factory.nullArgumentMethodCalled(null);
}
Mockito
I used nullable ()
because I couldn't check it with ʻany ()`.
SpockComponent1FactoryTest.groovy
@InjectMocks
SpockComponent1Factory spockComponent1Factory
@Mock
SpockComponent2Factory spockComponent2Factory
@Mock
SpockComponent2 spockComponent2
@Mock
SpockComponent3 spockComponent3
@Mock
SpockComponent4 spockComponent4
def setup() {
initMocks(this)
}
def "NullArgumentMethodCall -Call count check failed"() {
when:
spockComponent1Factory.nullArgumentMethodCall()
then:
verify(spockComponent2Factory, times(1)).nullArgumentMethodCalled(any(String.class)) || true
}
def "NullArgumentMethodCall -Successful call count check"() {
when:
spockComponent1Factory.nullArgumentMethodCall()
then:
verify(spockComponent2Factory, times(1)).nullArgumentMethodCalled(nullable(String.class)) || true
}
Spock The Spock side worked without any problems.
SpockComponent1FactoryTestSpock.groovy
SpockComponent1Factory spockComponent1Factory
SpockComponent2Factory spockComponent2Factory
SpockComponent2 spockComponent2
SpockComponent3 spockComponent3
SpockComponent4 spockComponent4
def setup() {
spockComponent2Factory = Mock(SpockComponent2Factory.class)
spockComponent2 = Mock(SpockComponent2.class)
spockComponent3 = Mock(SpockComponent3.class)
spockComponent4 = Mock(SpockComponent4.class)
}
def "NullArgumentMethodCall -Check the number of calls"() {
when:
spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
spockComponent1Factory.nullArgumentMethodCall()
then:
spockComponent2Factory.nullArgumentMethodCalled(_ as String)
}
}
As I mentioned at the beginning, it may be possible to make the test code more readable by actually creating an instance than by mocking it, so it seems better to write it while thinking (also as a commandment to yourself).
Recommended Posts