仅当传递给定 class 的任何 *non-null* 对象时才模拟方法 return 一个值

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

我正在使用 Mockito 模拟一个方法 return 给定日期时的日期。

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

但是,当它传递一个 非空 日期对象时,我只希望它 return supplierDeliveryDate。 当传递 null 时,它应该 return 为空。

这可能吗?我该怎么做?

使用 ArgumentMatchers.isNull() 匹配器。

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

您可以使用匿名内部 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);
    }
}

但你真的应该想知道为什么你需要这种行为。

如果您编写了一个定义良好的测试用例,那么您应该确切地知道您的 mock 被调用的频率和参数。如果是这样,那么您可以只存根预期的调用,而不是使用条件行为连接您的模拟。

请注意,如果您的测试尽可能 'sharp',这将很有用。如果调用模拟的次数与预期不同,或者使用不同的参数,则测试应该失败。

您可以使用辅助方法:

public static <T> void validateAndMock(Supplier<T> ongoingStubbing, T mockedResponse) {
    if (mockedResponse != null) {
        when(ongoingStubbing.get()).thenReturn(mockedResponse);
    }
}

然后调用:

validateAndMock(() -> supplier.calculateDeliveryDate(any(Date.class)), supplierDeliveryDate);