简体   繁体   中英

Junit/Mockito unit with Spring bean dependencies

I need to test following method inside ProductManager class which is a Spring bean. productService a bean and injected into ProductManager class. I try to write a Junit test using Mockito, but it kept to invoke real productService.getProductIdList(email) method instead of mock. ProductService also has a @PostConstruct. Could anyone enlighten me what's wrong with my test code?

@Named(ProductManager.NAME)
public class ProductManager {

@Resource(name = ProductService.NAME)
private ProductService productService;    

    public static final String NAME = "productManager";

    public Set<Product> getProducts(String email) {
        Set<Integer> productList = productService.getProductIdList(email);
        Iterator<Integer> itr = productList.iterator();
        Set<Product> products = new HashSet<Product>();
        Product p = null;
        while (itr.hasNext()) {
            p = getProduct(itr.next());
            if (p != null) {
                products.add(p);
            }
        }
        return products;
    }


    public Product getProduct(Integer ProductId) {
        Product p = productService.getProduct(productId);
        return p;
    }

}

So far, I have following Junit test code.

@Test
public void getProductByEmail(){

    String email = "testfakeuser@gmail.com";

    ProductService  mockProductService = mock(ProductServiceImpl.class);

    Integer productId1 = 10000;
    Integer productId2 = 10002;

    Product p1 = mock(Product.class);
    Product p2 = mock(Product.class);
    when(p1.getProductId()).thenReturn(productId1);
    when(p2.getProductId()).thenReturn(productId2);

    Set<Integer> productIdSet = (Set<Integer>)mock(Set.class);
    productIdSet.add(productId1);
    productIdSet.add(productId2);
    Iterator<Integer> productIdIterator = (Iterator<Integer>)mock(Iterator.class);
    when(productIdSet.iterator()).thenReturn(productIdIterator);        
    when(mockProductService.getProductIdList(email)).thenReturn(productIdSet);
    when(productIdIterator.hasNext()).thenReturn(true, true, false);
    when(productIdIterator.next()).thenReturn(productId1).thenReturn(productId2);
    when(productManager.getProduct(productId1)).thenReturn(p1);
    when(productManager.getProduct(productId2)).thenReturn(p2);

    Set<Product> products = productManager.getProducts(email);
    assertEquals(2, products.size());

}

I don't see any where where you set your mocked ProductService in to the ProductManager object.

You've created a intricate set of related objects, but not asked the ProductManager to use it.

I am answering to my own question. I resolved the issue using Spring ReflectionTestUtils. It can set mock dependencies. I referenced http://romiawasthy.blogspot.com/2012/03/autowired-mockobjects-for-junits.html . I tried second solution, but I couldn't make it work. In this Test, the productManager is not mocked. It is a real spring bean. Another way of doing is don't use Spring context at all, just use Mockito RunWith(MockitoJUnitRunner.class). In this case all beans are mocked including the productManager. I did some research yesterday and using MockitoJUnitRunner.class is preferable since it can void reapeating code and you have full control of your test environment. Please look at this article for using MockitoJUnitRunner.class http://www.jayway.com/2012/02/25/mockito-and-dependency-injection/ . It is clear and simple.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:context-test.xml")
public class ProductManagerTest {

    @Inject
    private ProductManager productManager;
    @Test
    public void getProductByEmail(){

        String email = "testfakeuser@gmail.com";

        ProductService  mockProductService = mock(ProductServiceImpl.class);

        Integer productId1 = 10000;
        Integer productId2 = 10002;

        Product p1 = mock(Product.class);
        Product p2 = mock(Product.class);
        p1.setProductId(productId1);
        p2.setProductId(productId2);


        Set<Integer> productIdSet = (Set<Integer>)mock(Set.class);
        productIdSet.add(productId1);
        productIdSet.add(productId2);
        Iterator<Integer> productIdIterator = (Iterator<Integer>)mock(Iterator.class);
        when(productIdSet.iterator()).thenReturn(productIdIterator);        
        when(mockProductService.getProductIdList(email)).thenReturn(productIdSet);

        ReflectionTestUtils.setField(productManager, "mockProductService",
            mockProductService); 

        when(productIdIterator.hasNext()).thenReturn(true, true, false);
        when(productIdIterator.next()).thenReturn(productId1).thenReturn(productId2);
        when(productManager.getProduct(productId1)).thenReturn(p1);
        when(productManager.getProduct(productId2)).thenReturn(p2);

        Set<Product> products = productManager.getProducts(email);
        assertEquals(2, products.size());

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM