如何先编写单元测试并稍后编写代码?

时间:2013-09-25 11:43:42

标签: c# unit-testing nunit moq

我是单元测试的新手,并且多次读过我们应该首先编写单元测试然后再编写实际代码。截至目前,我正在编写我的方法,然后对代码进行单元测试。

  

如果你先写测试......

     

您倾向于编写适合测试的代码。这鼓励了   “解决问题的最简单的事情”类型开发并保持   你专注于解决没有解决元问题的问题。

     

如果您先编写代码......

     

您很想编写测试以适应代码。实际上是这个   相当于写出问题以适合你的答案,这是   倒退,往往会导致测试   价值较低。

听起来不错。但是,即使在我的代码到位之前,我如何编写单元测试? 我从字面上接受了这个建议吗?这是否意味着我应该有我的POCO类和接口,然后编写单元测试?

任何人都可以通过一个简单的例子说明如何添加两个数字来解释我是如何做到的?

4 个答案:

答案 0 :(得分:7)

真的很简单。红色,绿色,重构。

红色表示 - 您的代码已完全损坏。语法高亮显示红色,测试未通过。为什么?你还没有编写任何代码。

绿色表示 - 您的应用程序构建并且测试通过。您已添加了所需的代码。

重构意味着 - 清理它并确保测试通过。

你可以从写一个像这样的测试开始:

[TestMethod]
public void Can_Create_MathClass() {
    var math = new MathClass();
    Assert.IsNotNull(math);
}

这将失败( RED )。你是如何解决的?创建课程。

public class MathClass {
}

就是这样。它现在通过( GREEN )。下一个测试:

[TestMethod]
public void Can_Add_Two_Numbers() {
    var math = new MathClass();
    var result = math.Add(1, 2);
    Assert.AreEqual(3, result);
}

这也失败了( RED )。创建Add方法:

public class MathClass {
    public int Add(int a, int b) {
        return a + b;
    }
}

运行测试。这将通过( GREEN )。

重构是清理代码的问题。这也意味着您可以删除多余的测试。我们知道现在有MathClass ..因此您可以完全删除Can_Create_MathClass测试。完成后......您已通过 REFACTOR ,并可以继续。

重要的是要记住,重构步骤并不仅仅意味着您的正常代码。它也意味着测试。你不能让你的测试随着时间的推移而恶化。您必须将它们包含在Refactor步骤中。

答案 1 :(得分:2)

当您首先在代码之前创建测试时,您会发现创建代码更加容易和快捷。创建单元测试并创建一些代码以使其通过所需的组合时间与直接编码相同。但是,如果你已经进行了单元测试,那么在代码之后你就不需要创建它们了,现在又节省了一些时间。之后很多时间。

创建单元测试有助于开发人员真正考虑需要完成的工作。通过测试坚定地确定要求。不能误解以可执行代码形式编写的规范。

您将创建的代码简单明了,仅实现您想要的功能。其他开发人员可以通过浏览测试来了解如何使用此新代码。测试套件中显然不存在结果未定义的输入

系统设计也有好处。对某些软件系统进行单元测试通常非常困难。这些系统通常首先构建代码并进行第二次测试,通常由不同的团队完成。通过首先创建测试,您的设计将受到为客户测试所有有价值物品的愿望的影响。您的设计将通过更容易测试来反映这一点。

答案 2 :(得分:1)

让我们采用一个稍微更高级的示例:您想要编写一个返回序列中最大数字的方法。

首先,为要测试的方法编写一个或多个单元测试:

int[] testSeq1 = {1, 4, 8, 120, 34, 56, -1, 3, -13};

Assert.That(MaxOf(testSeq1) == 120);

重复一些序列。还包括一个null参数,一个带有一个元素和一个空序列的序列,并确定一个空序列或null参数是否应抛出一​​个异常(并确保单元测试需要一个空序列的异常,如果是这种情况)。

在此过程中,您需要确定方法的名称及其参数的类型。

此时,它将无法编译。

然后为方法编写一个存根:

public int MaxOf(IEnumerable<int> sequence)
{
    return 0;
}

此时它会编译,但单元测试失败。

然后实现MaxOf(),以便现在通过这些单元测试。

这样做可以确保您立即专注于方法的可用性,因为您尝试做的第一件事就是在开始编写之前使用它。您可能会根据使用模式决定稍微更改方法的声明。

一个真实世界的例子将这种方法应用于整个类,而不仅仅是一种方法。为简洁起见,我省略了上面例子中的类。

答案 3 :(得分:0)

可以在编写任何代码之前编写单元测试 - Visual Studio确实具有从您在单元测试中编写的代码生成方法存根的功能。这样做也可以帮助理解对象需要支持的方法 - 有时这有助于以后的增强(如果你有保存到磁盘,你也超载以保存到Stream,这是更多如果以后需要,可测试并辅助通过网络进行假脱机)