测试行为和嘲笑

时间:2012-07-05 11:15:01

标签: unit-testing mocking

在为更复杂的方法/类编写单元测试时,我仍然没有那么自信。我对tdd和单元测试的一般理解是,你应该能够重构一个类/方法的实现,并且有信心你没有改变它的行为

让我举一个例子来说明问题。

public class OrderService implements IOrderService
{
    private IItemService itemService;

    public Order create(OrderCreationDto dto)
    {
        Order order = new Order();
        order.addItems(createOrderLines(dto.products));
        return order;
    }

    private Set<OrderLine> createOrderItems(List<ProductDto> products)
    {
        Set<OrderLine> orderLines = new HashSet<>();
        for (ProductDto product : products) {
            Item item = itemService.create(product.id, product.price);
            OrderLine orderLine = new OrderLine();
            orderLine.setItemId(item.id);
            orderLines.add(orderLine);
        }
        return orderLines;
    }
}

基本上我只是从OrderCreationDto创建一个新订单。对于每个订单行,我必须首先使用商品服务来创建新商品。我的一个测试将确保使用某些参数为每个订单行调用itemService.create(...)

由于对itemService.create(...)的每次调用都非常昂贵,我想重构该课程以在一个请求中创建所有项目..让我们进行更改

public class OrderService implements IOrderService
{
    private Set<OrderLine> createOrderItems(List<ProductDto> products)
    {
        Set<OrderLine> orderLines = new HashSet<>();
        BatchItemCreationResponse response = itemService.createAll(products);
        for (ProductDto product : products) {
            Item item = response.get(product.id, product.price);
            ...
        }
        return orderLines;
    }
}

现在我已经进行了更改,我之前编写的测试失败了,即使班级的行为完全没有改变。

我错过了什么吗?这是我必须接受它的方式并简单地调整书面测试吗?

感谢任何想法

1 个答案:

答案 0 :(得分:1)

  

我错过了什么吗?这是我必须接受它的方式并简单地调整书面测试吗?

没有。是。

单元测试执行更改。您已根据某些类设置测试以使用某个合同(ItemService)。更改此合同需要您更改测试,就像那样简单。

以不同的方式思考:从经过测试的类客户端的角度来看,没有任何改变,行为也是一样的(这很好)。但是,从ItemService客户的角度来看,您已经引入了重大变更(合同变更)。谁是ItemService客户?在这种情况下,OrderService及其测试。

此外,您应该考虑状态验证(声明OrderService产品的状态)是否比行为验证更适合(验证模拟被称为)。前者通常会使你的测试对这些变化不那么脆弱,但两者都不会使引入变化的需要消失。