单元测试:自包含测试与代码重复(DRY)

Mic*_*ent 7 c# nunit unit-testing

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

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

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

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

我的班级看起来像这样:

[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. ...
}
Run Code Online (Sandbox Code Playgroud)

可以看出,我Job j = csvImporter.ImportJob(row); 在每个单元测试中都做了这一行,因为它们应该是自包含的.但这确实违反了DRY原则,并可能在某一天导致性能问题.

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

Ant*_*lev 5

您的测试类与通常的类没有什么不同,应该这样对待:所有良好实践(DRY,代码重用等)也应该适用于那里.


小智 4

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

[Test]
public void SomeTest()
{
   setupSomeSharedState();
   ...
}
Run Code Online (Sandbox Code Playgroud)

找到正确组合的一种方法可能是从没有 SetUp 方法开始,当您发现您正在重复测试设置代码时,请重构为共享方法。