如何在 NUnit 中要求至少 N 个断言为 运行?
How to require at least N assertions to be run in NUnit?
使用 QUnit,我可以 explicitly expect
在我的测试中 运行 特定数量的断言(哎呀,默认情况下至少需要 1 个断言,否则测试会失败)。
有什么方法可以用 NUnit 做类似的事情吗? (哎呀,默认情况下没有断言的测试甚至可以通过...)。
为澄清起见,这里有一个示例/重现。假设我正在试驾这段代码:
public class Util
{
public static void MyMethod(Action someAction)
{
// We're TDD'ing, and we are *just about* to write:
//someAction();
}
}
然后在我编写 someAction();
调用之前,我想编写一个测试。这是我想要写的测试:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
Assert.Expect(1); // Pseudo code, but this doesn't work.
Util.MyMethod(() => Assert.That(true));
}
当然我可以解决这个问题:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
bool wasCalled = false;
Util.MyMethod(() => wasCalled = true);
Assert.That(wasCalled);
}
而且我想我什至可以在 Assert
上编写自己的扩展方法来在一行中完成此操作,但我想知道 是否有惯用的/内置的方式来 "expect N assertions" 与 NUnit?
哪里没有内置工具。
建议自己实现。
如果只想要一次,可以这样:
[TestFixture]
public class myfixture {
[Test]
public void MyAssertCheckTest(){ // this test will fail if all other test fails
var mytests = new Action[]{Test1,Test2};
int failcount = mytests.Length;
foreach(var test in mytests){
try{
test();
}catch{
if(--failcount==-1){
Assert.Fail("too many fails");
}
}
}
}
[Test]
[Explicit] //mark it explicit - we want to check it only if MyAssertCheckTest fails
public void Test1(){
Assert.True(false);
}
[Test]
[Explicit]
public void Test2(){
Assert.True(true);
}
}
此示例显示了 NUnit 中不包含此类内容的原因之一 - 语义不太清晰(为什么我们允许某些内容失败?)
如果你想像往常一样使用它,我认为最好的方法是使用 [Suite]
而不是 [TestFixture]
并实现自己的带下划线测试的调用程序。
或自己制作 MyAsserts.AtLeast(int failcount, params Action[] subtests)
或类似的东西。
根据之前的回答讨论。
Assert 不是对您的场景有用的 class。如果你真的想要,可以自己制作 class
如果使用断言。
var failcount = 3;
try{
Assert.AreEqual(false,true);
}catch(AssertException e){
if((--failcount)==-1){
throw e;
}
}
我觉得很丑。断言总是抛出错误,所以如果你想明确说明,请以其他方式做到这一点。
因此您可以重写 NUnit 并添加这样做的可能性并发出池请求,如果没有,它仍然需要写入
作为变体:
1) 为 ex QAssert 编写自己的断言,可以选择在定义 FailCount 的地方获取 QContext,它可以是 Assert
的包装器
public static QAssert {
public static bool AreEqual ( object a, object b, QContext context ) { //while it's not fail sometimes while it's not AreEqual it should return bool
if(null==context || context.FailAvailable<=0) {
Assert.AreEqual(a,b);
return true;
}
try{
Assert.AreEqual(a,b);
return true;
}catch(AssertExceptio e){
context.FailAvailable--;
context.FailedTests.Add(MethodBase.GetCurrentMethod());
return false;
}
}
}
那么在你的测试中
[Test]
public void MultiFail(){
var context = new QContext{AvailFail=2};
QAssert.False(true, context); //AvailFail=1
QAssert.True(false, context); //AvailFail=2
QAssert.True(true, context);
}
测试将通过
如果你真的想让它变酷,你可以用属性、StackTrace 创造你自己的魔法,教你的 QAssert 自动初始化 QContext 并使用它:
[Test]
[QContext(AvailFail=2)]
public void MultiFail(){
QAssert.False(true); //AvailFail=1
QAssert.True(false); //AvailFail=2
QAssert.True(true);
}
它确实可以通过内部静态 Dictionary<MethodInfo,QContext>
、QContextAttribute
和 StackTrace.GetFrame(...)
来实现 - 如果显式 QContext 为 null QAssert 的查找 StackTrace 并找到具有 Test 属性的最接近的方法,那么它查看字典 - 如果仍然没有字典(测试中的第一个断言) - 它使用 QContextAttribute 初始化它(如果附加到方法) - 然后它使用它,所有后续 QAssert 调用将使用缓存字典。
这是非常简单的实现 - 它不是免费的缓存字典,所以如果一个测试将被调用两次,它将重用不太好的上下文,但对于大多数情况,这个模式可以工作。
首先,对于某些上下文(因为这个问题似乎主要是关于“N=1
”(即期望在每个测试中至少有一个断言))一位 NUnit 作者给出了一些关于 N=1
的见解on Google Groups:
We once considered requiring an assertion in each test, failing it
otherwise. We also considered giving an Inconclusive result in such a
case. Both ran afoul of a fairly common usage where folks simply make
a call, verifying that no exception is thrown. I don't like such tests
myself but since some people use them we felt they had to be
supported.
早些时候在同一个线程中也清楚地表明,NUnit 用户无法访问 运行 的断言数量是有意为之的。给出的一些推理:
Generally, we don't think your test should know anything about the
test infrastructure. NUnit's count of asserts is something private to
NUnit, until it is tallied up for the final result of the test. It may
include asserts executed in setup, by the test itself or even in
teardown - though that's not recommended. It may include asserts
executed by ActionAttributes placed on the test, the fixture or on a
higher level suite. For your test to know how many asserts will be
executed, it has to know pretty much everything about the environment
in which it is being run. That defeats the whole idea of test
independence.
简而言之,这是不可能的。要么使用@ФагимСадыков 给出的其他答案之一,要么遵循 Google 组的建议:
The "workaround" you show is pretty much the normal way of checking
that a callback was called in NUnit, xUnit, mbUnit and mstest
也就是这种类型的测试:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
bool wasCalled = false;
Util.MyMethod(() => wasCalled = true);
Assert.That(wasCalled);
}
底线:在 NUnit 中检查(或期望)断言的数量 运行 是不可能的。
使用 QUnit,我可以 explicitly expect
在我的测试中 运行 特定数量的断言(哎呀,默认情况下至少需要 1 个断言,否则测试会失败)。
有什么方法可以用 NUnit 做类似的事情吗? (哎呀,默认情况下没有断言的测试甚至可以通过...)。
为澄清起见,这里有一个示例/重现。假设我正在试驾这段代码:
public class Util
{
public static void MyMethod(Action someAction)
{
// We're TDD'ing, and we are *just about* to write:
//someAction();
}
}
然后在我编写 someAction();
调用之前,我想编写一个测试。这是我想要写的测试:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
Assert.Expect(1); // Pseudo code, but this doesn't work.
Util.MyMethod(() => Assert.That(true));
}
当然我可以解决这个问题:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
bool wasCalled = false;
Util.MyMethod(() => wasCalled = true);
Assert.That(wasCalled);
}
而且我想我什至可以在 Assert
上编写自己的扩展方法来在一行中完成此操作,但我想知道 是否有惯用的/内置的方式来 "expect N assertions" 与 NUnit?
哪里没有内置工具。 建议自己实现。
如果只想要一次,可以这样:
[TestFixture]
public class myfixture {
[Test]
public void MyAssertCheckTest(){ // this test will fail if all other test fails
var mytests = new Action[]{Test1,Test2};
int failcount = mytests.Length;
foreach(var test in mytests){
try{
test();
}catch{
if(--failcount==-1){
Assert.Fail("too many fails");
}
}
}
}
[Test]
[Explicit] //mark it explicit - we want to check it only if MyAssertCheckTest fails
public void Test1(){
Assert.True(false);
}
[Test]
[Explicit]
public void Test2(){
Assert.True(true);
}
}
此示例显示了 NUnit 中不包含此类内容的原因之一 - 语义不太清晰(为什么我们允许某些内容失败?)
如果你想像往常一样使用它,我认为最好的方法是使用 [Suite]
而不是 [TestFixture]
并实现自己的带下划线测试的调用程序。
或自己制作 MyAsserts.AtLeast(int failcount, params Action[] subtests)
或类似的东西。
根据之前的回答讨论。 Assert 不是对您的场景有用的 class。如果你真的想要,可以自己制作 class 如果使用断言。
var failcount = 3;
try{
Assert.AreEqual(false,true);
}catch(AssertException e){
if((--failcount)==-1){
throw e;
}
}
我觉得很丑。断言总是抛出错误,所以如果你想明确说明,请以其他方式做到这一点。
因此您可以重写 NUnit 并添加这样做的可能性并发出池请求,如果没有,它仍然需要写入
作为变体: 1) 为 ex QAssert 编写自己的断言,可以选择在定义 FailCount 的地方获取 QContext,它可以是 Assert
的包装器public static QAssert {
public static bool AreEqual ( object a, object b, QContext context ) { //while it's not fail sometimes while it's not AreEqual it should return bool
if(null==context || context.FailAvailable<=0) {
Assert.AreEqual(a,b);
return true;
}
try{
Assert.AreEqual(a,b);
return true;
}catch(AssertExceptio e){
context.FailAvailable--;
context.FailedTests.Add(MethodBase.GetCurrentMethod());
return false;
}
}
}
那么在你的测试中
[Test]
public void MultiFail(){
var context = new QContext{AvailFail=2};
QAssert.False(true, context); //AvailFail=1
QAssert.True(false, context); //AvailFail=2
QAssert.True(true, context);
}
测试将通过
如果你真的想让它变酷,你可以用属性、StackTrace 创造你自己的魔法,教你的 QAssert 自动初始化 QContext 并使用它:
[Test]
[QContext(AvailFail=2)]
public void MultiFail(){
QAssert.False(true); //AvailFail=1
QAssert.True(false); //AvailFail=2
QAssert.True(true);
}
它确实可以通过内部静态 Dictionary<MethodInfo,QContext>
、QContextAttribute
和 StackTrace.GetFrame(...)
来实现 - 如果显式 QContext 为 null QAssert 的查找 StackTrace 并找到具有 Test 属性的最接近的方法,那么它查看字典 - 如果仍然没有字典(测试中的第一个断言) - 它使用 QContextAttribute 初始化它(如果附加到方法) - 然后它使用它,所有后续 QAssert 调用将使用缓存字典。
这是非常简单的实现 - 它不是免费的缓存字典,所以如果一个测试将被调用两次,它将重用不太好的上下文,但对于大多数情况,这个模式可以工作。
首先,对于某些上下文(因为这个问题似乎主要是关于“N=1
”(即期望在每个测试中至少有一个断言))一位 NUnit 作者给出了一些关于 N=1
的见解on Google Groups:
We once considered requiring an assertion in each test, failing it otherwise. We also considered giving an Inconclusive result in such a case. Both ran afoul of a fairly common usage where folks simply make a call, verifying that no exception is thrown. I don't like such tests myself but since some people use them we felt they had to be supported.
早些时候在同一个线程中也清楚地表明,NUnit 用户无法访问 运行 的断言数量是有意为之的。给出的一些推理:
Generally, we don't think your test should know anything about the test infrastructure. NUnit's count of asserts is something private to NUnit, until it is tallied up for the final result of the test. It may include asserts executed in setup, by the test itself or even in teardown - though that's not recommended. It may include asserts executed by ActionAttributes placed on the test, the fixture or on a higher level suite. For your test to know how many asserts will be executed, it has to know pretty much everything about the environment in which it is being run. That defeats the whole idea of test independence.
简而言之,这是不可能的。要么使用@ФагимСадыков 给出的其他答案之一,要么遵循 Google 组的建议:
The "workaround" you show is pretty much the normal way of checking that a callback was called in NUnit, xUnit, mbUnit and mstest
也就是这种类型的测试:
[Test]
public void MyMethod_WhenGivenAction_ShouldCallAction()
{
bool wasCalled = false;
Util.MyMethod(() => wasCalled = true);
Assert.That(wasCalled);
}
底线:在 NUnit 中检查(或期望)断言的数量 运行 是不可能的。