我正在使用Mockito编写集成测试。
被测单元通过接口连接到模拟对象(objA)。我尝试模仿的功能发生在被模拟的对象触发事件并且被测单元正在监听该事件时。

界面:

public interface MyInterfaceAPI{
   void fireyMyEvent(String msg);
}


被测单元:

public class UnitUnderTest{

    ObjA objA;

    public UnitUnderTest(ObjA objA_t) {
         objA = objA_t;
         objA.addMyListener(new addMyHandler());
    }

    class addMyHandler implements MyInterfaceAPI{
       @Override
       public void fireyMyEvent(String msg) {
             System.out.println(msg);
       };
    };
};


考试:

 public class MyTest {

     @org.junit.Test
     public void run() {

         ObjA  mockObjA = mock(ObjA .class);
         UnitUnderTest spyController = Mockito.spy(new UnitUnderTest());

         MyInterfaceAPI mo2uut= mock(MyInterfaceAPI.class);
         mo2uut.fireyMyEvent("hello from test");
     }
 }


我的问题是在测试中,如何将mo2uut(“模拟对象”与“被测单元”)连接到UnitUnderTest内部的MyInterfaceAPI的addMyHandler类实现?

我显然缺少一些东西,但是我不确定。

最佳答案

您有2所学校进行单元测试:伦敦/模拟学校和底特律学校。

如果要使用模拟,则必须使用依赖注入,以便可以用模拟替换依赖。我认为跟随底特律学校的大多数人也会同意这一点,只是因为使用依赖注入“是一件好事”(tm)。

您可以做的是在构造函数中将ObjA的实例传递给UnitUnderTest。或者(如果ObjA是一个集合)添加方法UnitUnderTest.addListener(),在其中传递处理程序的实例。通过这两种方法,您将注入一个处理程序。

关于使用powermock:Powermock是更好的野兽,可用于单元测试很少的旧项目,并且它们的依赖关系一团糟。如果您现在正在编写此代码,则使用电源模拟是错误的(出于公平的考虑,这是一个有偏见的想法,但它与其他许多人共享)。

编辑

现在我得到你的问题!而且我认为您要在一个单元测试中进行过多的测试,这会导致问题。再次,模拟派谈论有关测试交互的问题……这是关键。因此,在对UnitUnderTest的测试中,唯一的交互是与ObjA设置处理程序,这就是故事的结尾。

您可能会对ObjA进行另一项测试,以确保调用所有处理程序。

现在最后一点是如何测试处理程序的代码。但在此之前,请欣赏每个测试的独立性,因为您正在测试交互作用(以及代码中的任何逻辑),但不要超过一件事。
关于处理程序……您可能不喜欢这样,但是您必须使该类可访问,或者将其公开或将其提取到另一个公共类。如果将其提取,则可以放入internal包中,这样很明显该类不应被其他任何人使用。

如果您有一个小时的空闲时间,我建议您观看以下精彩的演示文稿:Michael Feathers撰写的The Deep Synergy Between Testability and Good Design,他在其中介绍了一个类似的示例,说明您的代码中有什么以及为什么分开它是有意义的。

10-08 17:11