I have class like this:
class A(B b, C c, D d, E e) {
protected void doSth() {
test();
}
protected void test() {
System.out.println("test");
}
}
and I am trying to test if doSth()
method is invoked then test()
method is also invoked. Methods are of returned type void so I cannot test result of these methods.
My tests looks like this
def "test when doSth"() {
given: 'A class'
A aClass = GroovySpy(A, constructorArgs: [GroovyMock(B), GroovyMock(C), GroovyMock(D), GroovyMock(E)) as A
when:
A.doSth()
then:
1 * A.test()
}
but this test does not work. It gives me "Too few invocations" error for test method. I am really confused because exactly same example but with no args in constructor works perfectly.
Firstly, I don't know what kind of syntax your Java class has. I guess it is not really Java but maybe something like Kotlin? I have no idea, I only speak Java and Groovy when it comes to JVM languages. So let me recreate your subject under test like this:
package de.scrum_master.stackoverflow.q56652868;
public class A {
private B b;
private C c;
private D d;
private E e;
public A(B b, C c, D d, E e) {
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
protected void doSth() {
test();
}
protected void test() {
System.out.println("test");
}
public static class B {}
public static class C {}
public static class D {}
public static class E {}
}
I hope this is okay.
As for your test, I am not sure if testing this interaction (method test()
called by doSth()
) is really essential to your application and should be tested in the first place. I think this kind of interaction testing is important for certain design patterns where you e.g. want to check if e.g. a subject notifies certain registered observers when something specific happens. Testing the inner wiring of a class, especially non-public methods, usually does not do much good and can lead to over-specification and brittle tests which need to be updated often if not the class's public API but just the internal implementation changes.
Having said that, now let me answer your question anyway for educational purposes.
Several things are wrong in your test:
]
for the constructor arguments list in the line defining your Groovy spy.A aClass = GroovySpy(A, ...) as A
you make 3x sure it is really an A
. Why not just A aClass = GroovySpy(...)
or maybe def aClass = GroovySpy(A, ...)
? No need to also convert an A
into itself via as A
.A.doSth()
and A.test()
as if you were dealing with static methods. Why? You need to write aClass.doSth()
and aClass.test()
, then your test will pass:package de.scrum_master.stackoverflow.q56652868
import de.scrum_master.stackoverflow.q56652868.A.B
import de.scrum_master.stackoverflow.q56652868.A.C
import de.scrum_master.stackoverflow.q56652868.A.D
import de.scrum_master.stackoverflow.q56652868.A.E
import spock.lang.Specification
class ATest extends Specification {
def "test when doSth"() {
given: 'A class'
A aClass = Spy(constructorArgs: [Mock(B), Mock(C), Mock(D), Mock(E)])
when:
aClass.doSth()
then:
1 * aClass.test()
}
}