与Mockito进行单元测试

xyz*_*xyz 6 spring unit-testing mockito

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

    @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;
        }
    }  
Run Code Online (Sandbox Code Playgroud)

这是我的测试课

@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);
    }    
}   
Run Code Online (Sandbox Code Playgroud)

它工作正常,但我几乎没有问题

  1. 我们如何Autowire在测试中提供服务?我在init()方法中使用构造函数来创建服务对象.
  2. 我们必须Autowire为服务类设置所有元素吗?对于前 StubRequestService已经自动连接RequestDao,我需要调用测试方法之前明确设定,否则giveds nullPointerException因为requestDaonullStubRequestService.getRequest方法.
  3. 在单元测试Spring服务层时,要遵循哪些好的做法?(如果我做错了什么).

JB *_*zet 7

你的测试很好.它甚至不必有@ContextConfiguration注释.

像Spring这样的依赖注入框架的整个要点是能够通过简单地实例化它们,设置模拟依赖项,然后调用它们的方法来对单元测试服务进行单元化.

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

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


bez*_*max 3

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

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

这意味着,您获取应用程序的一个单独的逻辑部分并测试它,同时完全模拟它尝试访问的所有内容。

假设您有三个课程:

//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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以在这里编写哪些测试?

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