Mockito和界面事件 [英] Mockito and interface event

查看:66
本文介绍了Mockito和界面事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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),他进入了一个类似的例子,说明了您的代码所包含的内容以及为何分开进行有意义的解释.

I am writing an integration test using mockito. The unit under test is connected to a mocked object (objA) through an interface. The functionality that I am trying to mimic happens when the mocked objected fires an event and the unit under test is listening to it.

The interface:

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

The unit under test:

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);
       };
    };
};

The test:

 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"); 
     }
 }

My question is in the test, how do I connect the mo2uut ('mocked object' to 'unit under test') to the addMyHandler class implementation of MyInterfaceAPI inside the UnitUnderTest?

I am clearly missing something, but I am not sure what.

解决方案

You have 2 schools on unit testing: The London / Mockist school, and the Detroit school.

If you want to use mocks, you must use dependency injection, so you can replace the dependencies with mocks. I think most people following the Detroit school would agree on this too, just because using dependency injection "is a good thing" (tm).

What you can do is to pass an instance of ObjA to UnitUnderTest in the constructor; Or alternatively (if ObjA is a collection) add the method UnitUnderTest.addListener(), where you pass an instance of a handler. With these 2 approaches, you'll be injecting a handler.

About using powermock: Powermock is a beast better used on old projects that have very little unit testing and their dependencies are a mess. If you are coding this now, using power mock is wrong (in the spirit of fairness, this is a biased idea, but it's shared with many other people).

Edit

Now I get your question! And I think that you're trying to test too much in one unit test and that causes the problem. Again, the mockist school talks about testing interactions... that's the key point. So in the test for UnitUnderTest the only interaction is with ObjA to set the handler, and that's the end of the story.

You'll probably have another test for ObjA to ensure that all handlers are invoked.

Now the last bit is how to test the code of the handler. But before that, please appreciate how independent each test is, as you're testing the interactions (and any logic in the code), but not more than 1 thing. About the handler... you might not like this, but you have to make that class accessible, either make it public or extract it to another public class. If you extract it, you can put in an internal package so it's clear that the class shouldn't be used by anyone else.

If you have an hour to spare, I would suggest you to watch this great presentation: The Deep Synergy Between Testability and Good Design by Michael Feathers where he goes into a similar example of what you have in your code and why it makes sense to separate it.

这篇关于Mockito和界面事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆