Search code examples
javamockingmockitomatcherhamcrest

Mock method to return a value only when passed any *non-null* object of a given class


I'm using Mockito to mock a method to return a Date when given a Date.

when(supplier.calculateDeliveryDate(any(Date.class)))
    .thenReturn(supplierDeliveryDate);

However, I only want it to return the supplierDeliveryDate when it is passed a non-null Date object. When passed null, it should return null.

Is this possible? How can I do it?


Solution

  • You could use an anonymous inner class:

    // unit test
    public OrderServiceTest {
    
        // instance of class-under-test
        private OrderService instance;
        // stub value
        private Date supplierDeliveryDate = new Date();
    
        // mock as an anonymous inner class
        private Supplier supplier = new Supplier() {
            public Date calculateDeliveryDate(Date input) {
                if (input == null) {
                    return null;
                }
                else {
                    return supplierDeliveryDate;
                } 
            }
        };
    
        @Before
        public void setUp() {
            instance = new OrderService();
    
            // dependency injection
            instance.setSupplier(supplier);
        }
    
        @Test
        public void testOrderHappy() {
            // SETUP
            Date orderDate = new Date();            
    
            // CALL
            Date result = instance.order(orderDate);
    
            // VERIFY
            assertTrue(supplierDeliveryDate == result);
        }
    
        @Test
        public void testOrderNull() {
            // SETUP
            Date orderDate = null;
    
            // CALL
            Date result = instance.order(orderDate);
    
            // VERIFY
            assertNull(result);
        }
    }
    

    But you should really wonder why you need this kind of behavior.

    If you write a well defined test case then you should know exactly how often, and with which arguments, your mock is called. If so, then you can just stub the expected calls instead of wiring your mock with conditional behavior.

    Note that is is useful if your test is as 'sharp' as possible. If a different number of calls hits your mock than expected, or with different arguments, then the test should fail.