单元测试:自包含测试与代码重复 (DRY) [英] Unit Testing: Self-contained tests vs code duplication (DRY)

查看:37
本文介绍了单元测试:自包含测试与代码重复 (DRY)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在进行单元测试的第一步,但不确定在单元测试中似乎自相矛盾的两种范式,即:

I'm making my first steps with unit testing and am unsure about two paradigms which seem to contradict themselves on unit tests, which is:

  • 每个单元测试都应该是独立的,而不是依赖于其他人.
  • 不要重复自己.

更具体地说,我有一个要测试的导入器.导入器有一个导入"功能,获取原始数据(例如从 CSV 中提取)并返回某种类型的对象,该对象也将通过 ORM(在本例中为 LinqToSQL)存储到数据库中.

To be more concrete, I've got an importer which I want to test. The Importer has a "Import" function, taking raw data (e.g. out of a CSV) and returning an object of a certain kind which also will be stored into a database through ORM (LinqToSQL in this case).

现在我想测试几件事情,例如返回的返回对象不为空,它的必填字段不为空或空,并且它的属性获得了正确的值.我为此编写了 3 个单元测试.每个测试都应该导入并获得工作还是属于通用设置逻辑?另一方面,相信这篇博文,就我的理解而言,后者将是一个坏主意.还有,这不会违反自控吗?

Now I want to test several things, e.g. that the returned object returned is not null, that it's mandatory fields are not null or empty and that it's attributes got the correct values. I wrote 3 unit tests for this. Should each test import and get the job or does this belong into a general setup-logic? On the other hand, believing this blog post, the latter would be a bad idea as far as my understanding goes. Also, wouldn't this violate the self-containment?

我的班级是这样的:

[TestFixture]
public class ImportJob
{
    private TransactionScope scope;
    private CsvImporter csvImporter;

    private readonly string[] row = { "" };

    public ImportJob()
    {
        CsvReader reader = new CsvReader(new StreamReader(
                    @"C:\SomePath\unit_test.csv", Encoding.Default),
                    false, ';');
        reader.MissingFieldAction = MissingFieldAction.ReplaceByEmpty;

        int fieldCount = reader.FieldCount;
        row = new string[fieldCount];

        reader.ReadNextRecord();
        reader.CopyCurrentRecordTo(row);
    }

    [SetUp]
    public void SetUp()
    {
        scope = new TransactionScope();
        csvImporter = new CsvImporter();
    }

    [TearDown]
    public void TearDown()
    {
        scope.Dispose();
    }

    [Test]
    public void ImportJob_IsNotNull()
    {
        Job j = csvImporter.ImportJob(row);

        Assert.IsNotNull(j);
    }

    [Test]
    public void ImportJob_MandatoryFields_AreNotNull()
    {
        Job j = csvImporter.ImportJob(row);

        Assert.IsNotNull(j.Customer);
        Assert.IsNotNull(j.DateCreated);
        Assert.IsNotNull(j.OrderNo);
    }

    [Test]
    public void ImportJob_MandatoryFields_AreValid()
    {
        Job j = csvImporter.ImportJob(row);
        Customer c = csvImporter.GetCustomer("01-01234567");

        Assert.AreEqual(j.Customer, c);
        Assert.That(j.DateCreated.Date == DateTime.Now.Date);
        Assert.That(j.OrderNo == row[(int)Csv.RechNmrPruef]);

    }

    // etc. ...
}

正如所见,我正在做这行 Job j = csvImporter.ImportJob(row); 在每个单元测试中,因为它们应该是独立的.但这确实违反了 DRY 原则,可能有一天会导致性能问题.

As can be seen, I'm doing the line Job j = csvImporter.ImportJob(row); in every unit test, as they should be self-contained. But this does violate the DRY principle and may possibly cause performance issues some day.

这种情况下的最佳做法是什么?

What's the best practice in this case?

推荐答案

这取决于测试中常见的场景有多少.在您提到的博客文章中,主要抱怨是 SetUp 方法对三个测试进行了不同的设置,这不能被视为最佳实践.在您的情况下,您对每个测试/场景都有相同的设置,然后您应该使用共享的 SetUp 而不是在每个测试中复制代码.如果您稍后发现有更多测试不共享此设置或需要在一组测试之间共享不同的设置,则将这些测试重构为新的测试用例类.您还可以共享未用 [SetUp] 标记但在每个需要它们的测试开始时调用的设置方法:

That depends on how much of your scenario that's common to your test. In the blog post you refered to the main complaint was that the SetUp method did different setup for the three tests and that can't be considered best practise. In your case you've got the same setup for each test/scenario and then you should use a shared SetUp instead of duplicating the code in each test. If you later on find that there are more tests that does not share this setup or requires a different setup shared between a set of tests then refactor those test to a new test case class. You could also have shared setup methods that's not marked with [SetUp] but gets called in the beginning of each test that needs them:

[Test]
public void SomeTest()
{
   setupSomeSharedState();
   ...
}

找到正确组合的一种方法可能是开始时不使用 SetUp 方法,当您发现要复制测试设置的代码时,然后重构为共享方法.

A way of finding the right mix could be to start off without a SetUp method and when you find that you're duplicating code for test setup then refactor to a shared method.

这篇关于单元测试:自包含测试与代码重复 (DRY)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆