与Mockito进行单元测试

时间:2011-12-28 12:24:28

标签: spring unit-testing mockito

我在春季应用程序中编写服务层的单元测试 这是我的服务类

    @Service
    public class StubRequestService implements RequestService {    
        @Autowired
        private RequestDao requestDao;  

        @Transactional(propagation = Propagation.REQUIRED, readOnly = true)
        @Override
        public Request getRequest(Long RequestId) {
            Request dataRequest = requestDao.find(requestId);
            return dataRequest;
        }
    }  

这是我的测试类

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" })
public class StubRequestServiceTest {

    @Mock
    public RequestDao requestDao;

    StubRequestService stubRequestService;  // How can we Autowire this ?

    @org.junit.Before
    public void init() {
      stubRequestService = new StubRequestService();  // to avoid this 
      stubRequestService.setRequestDao(dataRequestDao);  
      // Is it necessary to explicitly set all autowired elements ?  
      // If I comment/remove above setter then I get nullPointerException 
    }

    @Test
    public void testGetRequest()  {
        Request request = new Request();
        request.setPatientCnt("3");
        when(requestDao.find(anyLong())).thenReturn(request);
        assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3);
    }    
}   

它工作正常但我没有问题

  1. 我们如何在测试中Autowire服务类?我在init()方法中使用构造函数来创建服务对象。
  2. 我们是否必须为服务类设置所有Autowire元素?对于前StubRequestService我需要在调用测试方法之前明确设置的自动装配RequestDao,否则它会nullPointerException requestDao null StubRequestService.getRequest {{1}}方法。
  3. 单元测试Spring服务层时要遵循哪些好的做法? (如果我做错了什么)。

3 个答案:

答案 0 :(得分:7)

你的考试没问题。它甚至不必具有@ContextConfiguration注释。

像Spring这样的依赖注入框架的全部意义是能够通过简单地实例化它们,设置模拟依赖项,然后调用它们的方法来单元测试服务。

你正确地做到了。对于此类单元测试,您不需要具有Spring上下文。这就是为什么他们被称为单元测试:他们独立测试它的所有实际依赖,包括Spring。

附注:假设您正在使用JUnit,则应交换assertXxx方法的参数。预期值出现在实际值之前。当断言失败并且你有一个像“期待6但是3”而不是“期待3但是6”的消息时,它变得很重要。

答案 1 :(得分:3)

  1. 如果您真的觉得它会让您的测试更容易理解 - 您可以初始化弹簧上下文并从那里获取所有对象。但是,通常需要专门为测试创建一个单独的弹簧配置XML文件,因此我不推荐它。

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml");
    stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean");
    
  2. (和3)基本上,我更喜欢测试我的应用程序的每个组件与彼此完全隔离,这就是为什么我不推荐我在[1]中描述的内容。

  3. 这意味着,您是否对应用程序采用单独的逻辑片段并仅测试 ,而完全模拟它尝试访问的所有内容。

    我们假设您有三个班级:

    //Fetches stuff from some webservice and converts to your app domain POJOs
    class DataAccessLayer {
        public void setWebservice(Webservice ws) {...};
    
        public MyObject getMyObject() {...};
    }
    
    //Formats the domain POJOs and sends them to some kind of outputstream or stuff.
    class ViewLayer {
        public void setOutputStream(OutputStream os) {...};
    
        public void viewMyObject(MyObject mo) {...};
    }
    
    //Main entry point of our MyObject fetch-process-display workflow
    class Controller {
        public void setDataAccessLayer(DataAccessLayer dal) {...};
        public void setViewLayer(ViewLayer vl) {...};
    
        public void showMyObject() {
            MyObject mo = dal.getMyObject();
            ...some processing here maybe...
            vl.viewMyObject(mo);
        }
    }
    

    现在,我们可以在这里写什么测试?

    1. 测试DataAccessLayer是否将对象从模拟的 WS正确转换为我们的域对象。
    2. 测试ViewLayer是否正确格式化了提供给他的对象并将其写入模拟输出流。
    3. 测试Controller是否从模拟 DataAccessLayer获取对象,并将其正确处理并发送至模拟 ViewLayer

答案 2 :(得分:3)

或者您可以使用springockito https://bitbucket.org/kubek2k/springockito/wiki/Home,它会让你的测试变得更干净

相关问题