0

我正在学习单元测试,想知道这个单元测试程序流程(如 Arrange、Act、Assert)是否正确?

[TestFixture]
public class unitTest2
{
    private CoffeeMaker coffemaker;
    [Test]
    public void TestMethod1()       // Testa metoden för kaffe med mjölk. Uppgift 2(b)
    {
        coffemaker = new CoffeeMaker();                        //Arrange
        string res = coffemaker.MakeDrink(new Coffee(true, false));   //Act
        StringAssert.Contains("Coffee with milk", res);            //Assert
    }

}
4

3 回答 3

0

看起来不错,一些小改进:

[TestFixture]
public class CoffeeMakerUnitTests
{
    [Test]
    public void Test_MakeCoffeeWithMilk_Succeeds()
    {
        // Arrange
        var coffemaker = new CoffeeMaker();

        // Act
        string res = coffemaker.MakeDrink(new Coffee(true, false));

        // Assert
        StringAssert.Contains("Coffee with milk", res);
    }
}

Arrange/Act/Assert 模式以这种方式更加明显。并且您想避免任何不属于您的测试功能的事情,因为只有在您拥有第二个测试功能时才会造成麻烦。

您的函数应命名为“发生了什么以及预期结果是什么”,因为这样您就可以看到测试结果中的失败之处。“UnitTest1 failed”不是很具有描述性。

于 2015-04-19T13:18:29.847 回答
0

安排是您为测试设置所有内容的地方。Act 是您对 SUT(被测系统)执行某些操作的地方。断言是您验证该操作的结果的地方。

你的测试符合这个推理吗?是的。

您还应该考虑您正在使用的命名约定。以下是MethodName_Scenario_ExpectedResult测试方法名称:

[TestFixture]
public class CoffeeMakerTests
{
    [Test]
    public void MakeDrink_CoffeeWithMilk_ReturnsCorrectString() // Testa metoden för kaffe med mjölk. Uppgift 2(b)
    {
        // Arrange
        var coffeemaker = new CoffeeMaker();
        var coffeeWithMilk = new Coffee(true, false));

        // Act
        var resultString = coffeemaker.MakeDrink(coffeeWithMilk);

        // Assert
        StringAssert.Contains("Coffee with milk", resultString);
    }
}
于 2015-04-19T13:19:19.277 回答
0

该做什么和不该做什么

用它们的预期结果和被测试的状态或输入的相关细节来命名测试

给测试命名,除了被测试的方法的名称之外什么都不说,除非在微不足道的情况下

结构 三个不同块中的结构测试 -安排、行动和断言

单元测试往往具有非常规则的结构。引用这种结构的一种常见方式是安排、行动、断言:每个测试都必须安排世界的状态进行测试,通过调用方法作用于被测类,然后断言世界处于预期状态。

安排块用于设置特定于被测情况的外部世界的细节。这涉及到创建将在测试中重用的局部变量,有时还使用特定参数实例化被测对象。此步骤不应涉及对被测对象的任何调用(在动作块期间执行此操作)或初始状态的验证(在断言期间执行此操作,可能在另一个测试中执行)。请注意,所有或许多测试所需的一般设置应在测试的 setUp 方法中完成。如果您的测试不依赖于任何特定的外部状态,您可以跳过排列块。

act 块是您实际调用被测类以触发正在测试的行为的地方。通常这个块将是一个方法调用,但如果您正在测试的行为跨越多个方法,那么它们将在此处被调用。简单的参数可以作为方法调用的一部分内联,但更复杂的参数表达式有时最好提取到排列块中,以避免分散块的意图。act 块还可以将方法的返回值分配给局部变量,以便以后可以对其进行断言。

断言块是对收集的返回值进行断言并验证与模拟对象的任何交互的地方。它还可以构建断言和验证所需的值。在非常简单的测试中,act 和 assert 块有时通过将被测类的调用内联到 assert 语句中来组合。

这些块应该彼此不同——一旦在 act 块中调用被测类,测试不应执行任何额外的设置或存根,并且一旦在断言块。

在查看每个块开始和结束的测试时,应该清楚。通常这可以通过在每个块之间添加一个空行来完成(尽管在每个块只有一到两行的简单测试中这不是必需的)。在特别复杂的测试中,尤其是必须设置多个不同对象的测试中,您可能希望在块中使用空行以使其更具可读性。在这种情况下,区分这些块的一种方法是使用注释标记每个块,例如 // Arrange、//Act 和 // Assert。

强调这种结构的测试更清晰,因为它们可以轻松导航测试的不同部分,并且更有可能完成,因为常规结构有助于确保被测试行为的细节不会被隐藏或省略。

模拟框架以不同的方式与这个结构交互。大多数现代框架(如 Mockito)允许在排列块中配置存根以及定义局部变量,并在断言块中验证模拟以及执行断言。不幸的是,一些像 EasyMock 这样的旧框架需要在调用被测代码之前指定模拟的预期行为 - 这需要在 act 块之前的第四个“expect”块,其工作方式与 assert 块类似。

于 2018-08-07T09:54:04.710 回答