单元测试操作顺序

时间:2019-03-05 17:03:13

标签: c# unit-testing nunit

假设我们要做牛排。

Public class Restaurant{
    public void MakeSteak(Steak rawSteak) {
      this.KitchenServices.AddSeasoning(rawSteak);
      this.KitchenServices.Grill(rawSteak);
    }
}

在单元测试中,我可以确保给定一个生牛排,然后将其调味并烧烤:

public void MakeSteakTest() {
  var rawSteak = new Steak();
  this.restaurant.MakeSteak(rawSteak);
  this.KitchenServices.Verify(x => x.AddSeasoning(rawSteak) , Times.Once);
  this.KitchenServices.Verify(x => x.Grill(rawSteak) , Times.Once);
}

我的问题是,我们应该进行测试以确保牛排在烧烤后没有调味吗?如果是,怎么办?

3 个答案:

答案 0 :(得分:3)

通常,您应该在单元测试中测试结果,而不是实现。如果更改MakeSteak,以使操作按照不同的顺序进行,系统中会发生什么?那是可观察的东西吗?由于您唯一的意图是Steak对象,如果在Grill之前调用AddSeasoning,是否有某种验证会失败? 是您应该测试的。

答案 1 :(得分:1)

一种方法是将每个操作表示为对牛排进行操作的命令对象,例如。

interface ISteakOp {
    void DoTo(Steak s);
}

class AddSeasoningOp : ISteakOp { ... }
class GrillOp : ISteakOp { ... }

然后返回一系列操作:

public List<ISteakOp> MakeSteakOps() {
    return new List<ISteakOp> {
        new AddSeasoningOp(),
        new GrillOp()
    };
}

然后您的测试可以断言在进行任何调味之前都会发生任何烧烤操作:

var ops = MakeSteakOps();
var grillIndex = ops.IndexOf(o => o is GrillOp);
if (grillIndex != -1) {
    var seasonIndex = ops.IndexOf(o = o is AddSeasoningOp);
    Assert.That(seasonIndex == -1 || seasonIndex < grillIndex);
}

答案 2 :(得分:0)

  

我的问题是,我们应该进行测试以确保牛排在烧烤后没有调味吗?

首先:它对最终用户/利益相关者可见的行为有影响吗?

  

如果是,怎么办?

然后:

  • 如何能够检测到对行为的影响?在测试中使用相同的方法。
  • 用户期望的行为是什么?在测试中使用该期望值。

这听起来可能太“简单” /“过于简单”,但是我非常认真。那就是正确的行为测试的定义。