单元测试断言重复

发布于 2024-10-16 22:26:29 字数 752 浏览 2 评论 0原文

我正在研究 TDD 并在我当前的项目中进行实验。 我注意到我必须在测试中重复很多断言。 这是情况: 我有带有两个构造函数的 Order 类,第一个是默认的, 第二个有三个参数

Order(int customerId, int typeId, decimal amount)

在 OrderTests 类中,我正在检查分配是否正常工作

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500)

,我有订单服务类,具有以下创建订单方法,因为订单创建是复杂的过程。

Order CreateOrder(int cusotmerId, int typeId, int amount, moreParams...)

OrderServiceTests 类对此方法进行了测试,我需要使用相同的断言来检查是否已在 CreateOrder 服务中正确创建订单。

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500)
  1. 在测试中出现这样的重复可以吗?
  2. 在测试中提取具有相同断言的方法是否有意义,因为有时数量或重复的断言可能不止一个?或者这样的方法提取使测试变得不可读?

I'm studying TDD and experimenting it in my current project.
I've noticed that I have to duplicate a lot of asserts in my tests.
Here is situation:
I have Order class with two constructors first one is default and
second one has three params

Order(int customerId, int typeId, decimal amount)

In the OrderTests class I'm checking that assignments are working well

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500)

I have order service class with following create order method as order creation is complex process.

Order CreateOrder(int cusotmerId, int typeId, int amount, moreParams...)

OrderServiceTests class has test for this method and I need to use same assert to check that Order has been created correctly in the CreateOrder service.

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500)
  1. Is it ok to have such duplications in Tests?
  2. Is it make sense to extract methods with same assertions in tests as sometimes number or duplicated asserts maybe more then one? Or such method extractions make tests unreadable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

口干舌燥 2024-10-23 22:26:29

如果您有多种方法来创建对象,您可能需要测试每种创建方法(即参数化构造函数和工厂方法)的对象状态。因此,重复这些断言是有道理的。

在测试通过后的重构过程中(始终记住口头禅:红绿重构),如果您不仅在生产代码中而且在测试中发现重复,那么您应该通过使用提取方法重构来删除它。

[TestMethod]
public void if_parametrized_ctor_is_called_then_state_should_be_accordingly {
  var order = new Order(customerId, ...);
  ObjectPropertiesShouldBeSetTo(order, customerId, ...);
}

[TestMethod]
public void if_factory_method_is_called_then_state_should_be_accordingly {
  var order = myFactory.CreateOrder(customerId, ...);
  ObjectPropertiesShouldBeSetTo(order, customerId, ...);
}

// Extracted to remove code duplication
public void ObjectPropertiesShouldBeSetTo(Order order, int customerId, ...) {
  Assert.AreEqual(customerId, order.CustomerId);
  Assert.AreEqual(...);
}

如果您在一个 Assert 语句中检查多个条件(如示例所示),事情就会变得复杂。它降低了测试的可读性,并且如果任何一个条件失败,可能很难找到原因。

If you have multiple ways to create an object, you might want to test the object's state for each of the creation methods (i.e. parametrized constructor as well as factory method). Thus it makes sense to duplicate the assertions.

During refactoring after making your test pass (always remember the mantra: red-green-refactor) if you find duplication not only in your production code but also in your tests, then you should remove it by e.g. using the Extract Method refactoring.

[TestMethod]
public void if_parametrized_ctor_is_called_then_state_should_be_accordingly {
  var order = new Order(customerId, ...);
  ObjectPropertiesShouldBeSetTo(order, customerId, ...);
}

[TestMethod]
public void if_factory_method_is_called_then_state_should_be_accordingly {
  var order = myFactory.CreateOrder(customerId, ...);
  ObjectPropertiesShouldBeSetTo(order, customerId, ...);
}

// Extracted to remove code duplication
public void ObjectPropertiesShouldBeSetTo(Order order, int customerId, ...) {
  Assert.AreEqual(customerId, order.CustomerId);
  Assert.AreEqual(...);
}

It complicates things if you check multiple conditions within one Assert statement as in your example. It reduces test readability and it might be difficult to find the cause if any one of the conditions fails.

倾其所爱 2024-10-23 22:26:29

如果您需要对多个测试执行相同的对象验证,那么将这些断言拆分为通用方法是减少重复的好方法。在上面的示例中,您可以有一个名为 AssertObjectIsValid 的方法,并将公共代码移动到那里。

关于您的示例断言的另一件事。将多个检查组合在一个断言中使得从故障中确定哪个属性出现问题变得更加困难。如果您将这些断言分成单独的断言,并为每个断言提供消息,则将使跟踪错误变得更加容易(特别是如果您使用持续集成服务器,例如 CruiseControl.Net)。修改您的示例:

Assert.IsTrue(o.CustomerID == 5, "CustomerID doesn't match expected");
Assert.IsTrue(o.TypeId == 3, "TypeID doesn't match expected");
Assert.IsTrue(amount == 500, "Amount doesn't match expected");

If you need to perform the same object validation for multiple tests, splitting out those Asserts to a common method is a good way to reduce the duplication. In your example above, you could have a method called AssertObjectIsValid, and move the common code there.

One other thing regarding your example Assert. Combining multiple checks in a single Assert makes it more difficult to determine from a failure which property was at fault. If you split these into separate Asserts, and provide messages for each, it will make tracking down the error much easier (especially if you use a continuous integration server such as CruiseControl.Net.) Modifying your example:

Assert.IsTrue(o.CustomerID == 5, "CustomerID doesn't match expected");
Assert.IsTrue(o.TypeId == 3, "TypeID doesn't match expected");
Assert.IsTrue(amount == 500, "Amount doesn't match expected");
追我者格杀勿论 2024-10-23 22:26:29

是的,单元测试经常导致代码重复。但这种重复是有价值的。这个想法是,如果你用两种方式写同样的东西,你不太可能两次都犯同样的错误。这意味着你会发现很多愚蠢的错误。 (诚​​然,其中一半在您的单元测试代码中。)从代码自动生成单元测试会导致所有代码重复,但带来的好处却更少。

Yes, unit tests frequently cause duplication of code. But this duplication has value. The idea is that if you write the same thing in 2 ways, you're unlikely to make the same mistake both times. Which means that you will catch a lot of silly bugs. (Admittedly half of them are in your unit test code.) Automatically generating the unit tests from your code results in all of the code duplication, and fewer of the benefits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文