5

在编写单元测试时,我试图遵循 Arrange-Act-Assert 模式,但我对哪种方法会更好感到困惑。我正在使用 xUnit,我解决问题的第一种方法是:

//Arrange
int key = 1;
string value = "X";

//Act
board.Add(key, value);
var result = Assert.Throws<ArgumentException>(() => board.Add(key, value));

//Assert
Assert.IsType<ArgumentException>(result);

我的第二种方法是:

int key = 1;
string value = "X";

board.Add(key, value);

Assert.Throws<ArgumentException>(() => board.Add(key, value));

哪个是更好的方法?

编辑:在 wp.me/p4f69l-3z 上写博客

4

5 回答 5

6

你的第一个.Add电话应该是安排的一部分。将其视为行为的先决条件/设置。除此之外,您可以将act包装起来Action以使其更好地阅读:

//Arrange
int key = 1;
string value = "X";
board.Add(key, value);

//Act
Action addingSameKeySecondTime = () => board.Add(key, value);

//Assert
Assert.Throws<ArgumentException>(addingSameKeySecondTime)

评论中提到的FluentAssertions库使此类断言更加类似于句子

int key = 1;
string value = "X";
board.Add(key, value);

Action addingSameKeySecondTime = () => board.Add(key, value);

addingSameKeySecondTime.ShouldThrow<ArgumentException>();
于 2014-06-05T21:26:23.500 回答
1

我通常采取以下方法

// Arrange
int key = 1;
string value = "X";
board.Add(key, value);

// Act & Assert
Assert.Throws<ArgumentException>(() => board.Add(key, value));

这是 ASP.NET MVC 中采用的方法(例如https://aspnetwebstack.codeplex.com/SourceControl/latest#test/Common/PrefixContainerTest.cs

于 2014-06-19T09:20:26.270 回答
1

对我来说,源代码应该是自我描述的,所以 AAA 注释更像是解决方法,可能无法提供足够的灵活性。检查这个库:Heleonix.Testing 您可以像 JavaScript Jasmine/Jest 样式一样以 Given/When/Then 和 AAA 形式编写测试。

于 2018-03-21T17:49:56.373 回答
0

实际上,断言异常没有好的答案……这就像测试事件,只是它们会中断代码流。假设您将测试 add 事件(我正在使用 NUnit):

// Arrange
int key = 1;
var eventFired = false;
board.Added += (boardItem) => {
    eventFired = boardItem.key == key;
};

// Act
board.Add(key, "X");

// Assert
Assert.That(eventFired, Is.True);

测试异常时也是这样:

// Arrange
int key = 1;    
var exceptionRaised = false;
board.Add(key, "X");

// Act
try {
    board.Add(key, "X");
}
catch(InvalidOperationException ex) {
    exceptionRaised = true;
}

// Assert
Assert.That(exceptionRaised, Is.True);

所以 Assert.Throws 可以方便地使用,但它不适合 AAA 风格。但请记住,AAA 并不是写好测试的强制性要求,最重要的是让您的测试易于理解。

于 2014-06-05T21:16:01.990 回答
0

我会说你的第二个例子更好。Assert.Throws 将通过/失败测试,​​因此没有理由得到它的结果并断言。当我编写“将抛出”测试时,我将其保留在一两行:

[Test]
public void SomeMethod_NullSomething_ShouldThrow() {
    var something = MakeTarget();

    Assert.Throws<ArgumentNullException>(() => something.SomeMethod(null));
}
于 2014-06-05T21:00:43.743 回答