【问题标题】:Test anonymous class in Junit or Groovy/Spock test在 Junit 或 Groovy/Spock 测试中测试匿名类
【发布时间】:2019-11-14 16:58:41
【问题描述】:

我正在尝试在 Groovy/Spock 中编写单元测试,并且必须测试以下代码。

public class ClassA {
    @Inject
    private ClassB classB;

    @Inject
    private ClassC classC;

    @Inject
    private ClassD classD;

    public void update(final int a, final Map<String, Object> b) {
        classB.executeCommand(classC.callToMethodInClassC(), new InterfaceE<Void>() {
            @Override
            public Void execute() {
                classD.update(a, b);
                return null;
            }
        });
    }
}

现在,当我编写测试代码时,我无法到达classD.update(a, b); 行。我知道如何为 ClassB、ClassC、ClassD 注入模拟/真实对象,但无法达到该声明。请帮忙。

注意: ClassA.update() & ClassD.update() 除了签名匹配外,没有任何关系。

【问题讨论】:

  • 几个问题来澄清您的用例。 1) 你是模拟classB 还是使用真正的实现? 2) executeCommand 是异步方法还是同步方法?如果你模拟classB,那么你的方法什么也不做——它执行空模拟。如果您使用真实对象并且该方法是异步的,您可能需要使用一些等待机制,以便您的测试方法在完成异步调用之前不会完成。根据我在您的示例中看到的内容,我只能告诉您这些。它遗漏了很多上下文和细节,我们只能猜测。
  • 抱歉回来晚了。 (1) 我可以模拟 ClassB,因为我的单元测试可以达到classD.update(a, b); (2) 异步,最后,我无法理解你在最后一个语句中的意思。另外,如果您需要更多详细信息,请提及。我会尽量提供相同的。

标签: java unit-testing groovy ejb spock


【解决方案1】:

像这样模拟你的 classB:

Mock(ClassB) {
    executeCommand(_, _) >> { c, e -> e.execute() }
}

即为 ClassB 的 executeCommand 方法提供一个模拟实现,它实际上调用了 interfaceE 的 execute 方法。

编辑:完整的工作示例:

import spock.lang.Specification

class TestMeSpec extends Specification {

    def "my test"() {
        def b = Mock( ClassB ) {
            executeCommand( _, _ ) >> { c, e -> e.execute() }
        }
        def c = Mock( ClassC )
        def d = Mock( ClassD )

        def a = new ClassA( classB: b, classC: c, classD: d )

        when:
        a.update( 0, [ : ] )

        then:
        1 * d.update( 0, [ : ] )
    }
}

class ClassA {
    ClassB classB
    ClassC classC
    ClassD classD

    void update( final int a, final Map<String, Object> b ) {
        classB.executeCommand( classC.callToMethodInClassC(), new InterfaceE<Void>() {
            @Override
            Void execute() {
                classD.update( a, b )
            }
        } )
    }
}

class ClassB {
    void executeCommand( c, InterfaceE e ) {
        println "REAL CLASS B executCommand() METHOD RUNNING"
    }
}

class ClassC {
    def callToMethodInClassC() {}
}

class ClassD {
    void update( a, b ) {
        println "REAL CLASS D update() method called with $a and $b"
    }
}

interface InterfaceE<T> {
    T execute()
}

【讨论】:

  • 抱歉回来晚了。但是当 e 属于接口的匿名实例时,我如何在这里引用“e”。如果我在本地创建一个新实例,那么流程将通过它而不是通过实际代码。
  • 你的测试代码调用classA.update(),它调用classB.executeCommand(),传递两个参数给它,第二个是InterfaceE的实例。现在,classB 是一个 Mock,所以 mock 的 executeCommand 方法是被调用的,正如我上面所展示的,你可以提供一个 lambda(作为该方法的假实现),它接受 args 并做一些事情在这个例子中,他们在提供的InterfaceE 实例上调用execute()
猜你喜欢
  • 2021-06-11
  • 1970-01-01
  • 2018-09-08
  • 2016-07-13
  • 1970-01-01
  • 1970-01-01
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多