模拟不起作用

时间:2015-11-11 18:49:11

标签: java junit mocking mockito amazon-dynamodb

每当我运行以下代码时,我都会收到错误:

Wanted but not invoked:
dynamoDBWriter.addItemsToDynamoTable(
    <any>,
    <any>
);
-> at DynamoDBWriterTest.testAllItemsAdded(DynamoDBWriterTest.java:32)

However, there were other interactions with this mock:
dynamoDBWriter.write(
    [{ Item: {} }, { Item: {} }, { Item: {} }, { Item: {} }, { Item: {} }]
);
-> at DynamoDBWriterTest.testAllItemsAdded(DynamoDBWriterTest.java:31)

以下是我的代码:

public class DynamoDBWriterTest {

    DynamoDBWriter dynamoDbWriter;

    @Before
    public void setup() {
        dynamoDbWriter = mock(DynamoDBWriter.class);
    }

    @Test
    public void testAllItemsAdded() {
        List<Item> items = new ArrayList<>();
        for (int index = 0; index < 5; index++) {
            items.add(new Item());
        }
        dynamoDbWriter.write(items);
        verify(dynamoDbWriter, times(5)).addItemsToDynamoTable(any(), any());
    }
}

DynamoDBWriter的代码:

public void write(List<Item> items) {
        // Initialize the rate limiter to allow capacity units / sec
        // Since we know that the Item we are putting consumes 1 unit throughput.
        RateLimiter rateLimiter = RateLimiter.create(1);

        // Track how much throughput we consume on each put operation
        for (Item item: items) {
            // Let the rate limiter wait until our desired throughput "recharges"
            rateLimiter.acquire();
            addItemsToDynamoTable(table, item);
        }
    }

    protected void addItemsToDynamoTable(Table table, Item item) {
        try {
            table.putItem(item);
        } catch (RuntimeException e) {
            logger.fatal("dynamoDB table.putItem threw exception for:" + tableName, e);
            throw e;
        }
    }

感谢您的帮助。我还要添加实际的&#34;更正/工作&#34;我用过的代码:

@Before
    public void setup() {
        dynamoDbWriter = spy(DynamoDBWriter....);
        doNothing().when(dynamoDbWriter).addItemsToDynamoTable(any(), any());
    }

    // Method makes sure that irrespective of the throughput, all the items are added to dynamoDB
    @Test
    public void testAllItemsAdded() {
        List<Item> items = new ArrayList<>();
        for (int index = 0; index < 5; index++) {
            items.add(new Item());
        }
        dynamoDbWriter.write(items);
        verify(dynamoDbWriter, times(5)).addItemsToDynamoTable(any(), any());
    }

2 个答案:

答案 0 :(得分:1)

创建模拟 DynamoDBWriter时,默认情况下会使用无操作存根覆盖所有方法。当您致电write时,Mockito的替代实施允许验证write被称为,但不能 write实施所做的任何调用。永远不会调用该实现。

当然,真正的问题是你嘲笑你正在测试的课程。即使使用技术解决方案,也可以非常轻松地测试模拟框架,而不是模拟测试中的类。通常,为您的被测系统的协作者保留模拟,而不是您正在测试的系统本身。 (另见JB Nizet与his answer here的类比。)

那就是说,如果绝对必要,你可以使用实际实例的spy并根据需要有选择地覆盖方法,或者更危险的是你可以在模拟上使用thenCallRealMethod

when(dynamoDbWriter.write(any())).thenCallRealMethod();

对于两者之间的差异,以及为什么thenCallRealMethod如此危险,请参阅this SO question

答案 1 :(得分:1)

你在嘲笑DynamoDBWriter,这意味着对它的调用并没有真正被调用(它们被调用,但它们中的内部代码没有被执行,它只是一个模拟)。 所以你在这里得到的错误是因为只执行了write,而不是addItemsToDynamoTable

你在这里嘲笑错误的对象 - 如果你想测试DynamoDBWriter,你不应该嘲笑它,你应该模拟它使用的外围对象。

在这种情况下,我是模拟表,验证table.put执行了5次(从代码中不确定如何构造DynamoDBWriter并将表传递给它,但我想你可以将模拟表传递给它)