我应该在哪个级别上测试我的逻辑

时间:2018-07-27 09:52:40

标签: c# tdd

我有一个TextGenerator类,该类使用MarkovChain类生成随机文本。从MarkovChain创建下一个单词的逻辑位于ChainNavigator类中:

public class TextGenerator
{
    public List<string> MakeText(int requiredTextLength, string sourceText)
    {
        var chain = new MarkovChain(sourceText);
        var chainNavigator = new ChainNavigator(chain);            
        var nextWord = chainNavigator.GetNextWord(/*params here*/);
    }
}

internal class ChainNavigator
{
    internal string GetNextWord(/*params here*/) { }
}

MarkovChain是从源文本生成的。源文本的最后一个单词将没有任何“下一个状态”,因为它后面没有任何单词。生成长文本时,ChainNavigator将到达最后一个单词,并且不知道返回什么。

我想测试TextGenerator在到达最后一个单词时开始新句子,并且该测试可以写在2个地方。

一方面,在TextGenerator中对此进行测试很有意义,因为它是我的外部接口:

[TestClass]
public class TextGeneratorTest
{
    [TestMethod]
    public void ShouldAppendADot_WhenEndOfChainReached()
    {
        var generator = new TextGenerator();
        var sourceText = "free men can remain free or sell their freedom";
        var firstWord = "their";
        var requiredTextLength = 2;

        var text = generator.MakeText(requiredTextLength, sourceText, firstWord);

        Assert.AreEqual("freedom.", text[1]);
    }
}

另一方面,经过测试的实际逻辑属于ChainNavigator类,在这里进行测试很有意义:

[TestMethod]
public void AppendADot_WhenEndOfChainReached()
{
    var sourceText = "free men can remain free or sell their freedom";
    var chain = new Chain(sourceText);
    var navigator = new ChainNavigator(chain);

    var nextWord = navigator.GetNextWord("their", 1);

    Assert.AreEqual("freedom.", nextWord);
}

在两个地方都这样做似乎是重复的。在哪里做得更好?

1 个答案:

答案 0 :(得分:0)

你的困惑其实很常见。其来源是“单元测试”中的“单元”一词。很多人会告诉你,“单元”就像一个单一的类,甚至只是一个单一的方法。几十年来,人们一直在说这个,但大多是错误的。这种误解源于这样一个事实,即您很少在书籍、文章和博客中看到真正的应用程序经过测试。由于很难用完整的应用程序展示单元测试的一般原则,因此示例通常仅限于非常少的类。甚至 Kent Beck 也在他的书中使用了著名的 Money 类示例,该示例主要限于单个类。

在不受外部细节约束的最高级别进行测试。在您有限的示例中,TestGenerator 可能只是完美级别。它可以让您完全测试您的业务逻辑,而不会在您更改内部结构时中断测试。如果您决定将 ChainNavigator 拆分为多个类或使用 ChainNavigator 加入 MarkovChain,您的测试不需要知道并且不会中断。