题
我们有一些关测试,访问该数据库。当他们中的一个失败,它可以让数据库的不一致状态-这是不是一个问题,因为我们重建数据库对每一个测试运行,但它可能会导致其他的测试失败,在相同的运行。
是它可以检测到,其中一项测试失败和执行某些清理?
我们不希望写清理代码在每一个测试,我们已经这样做了,现在。我想向执行清除在拆除,但只有当的测试失败了,因为清理可能是昂贵的。
更新:澄清-我想测试,以简单并不包括任何清理或错误的处理逻辑。我也不想执行数据库的重置在每个试验运行的,如果只考试失败。和这个代码也许应该执行的拆除方法,但是我不知道任何方式获得的信息,如果测试我们目前正在撕裂下来的失败或成功。
Update2:
[Test]
public void MyFailTest()
{
throw new InvalidOperationException();
}
[Test]
public void MySuccessTest()
{
Assert.That(true, Is.True);
}
[TearDown]
public void CleanUpOnError()
{
if (HasLastTestFailed()) CleanUpDatabase();
}
我正在寻找执行HasLastTestFailed()
解决方案
这个想法让我感兴趣,所以我做了一点挖掘。关没有这种能力,但有一个整体的扩展框架提供有呢?我找到了 这个伟大的条约的延伸呢 -这是一个良好的起点。后玩弄了,我提出了以下方案:一个方法装饰的一个自定义 CleanupOnError
属性将被称为如果一个测试在固定装置失败。
这里是如何测试的样子:
[TestFixture]
public class NUnitAddinTest
{
[CleanupOnError]
public static void CleanupOnError()
{
Console.WriteLine("There was an error, cleaning up...");
// perform cleanup logic
}
[Test]
public void Test1_this_test_passes()
{
Console.WriteLine("Hello from Test1");
}
[Test]
public void Test2_this_test_fails()
{
throw new Exception("Test2 failed");
}
[Test]
public void Test3_this_test_passes()
{
Console.WriteLine("Hello from Test3");
}
}
那里的属性是简单:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CleanupOnErrorAttribute : Attribute
{
}
这里是它是如何执行从addin:
public void RunFinished(TestResult result)
{
if (result.IsFailure)
{
if (_CurrentFixture != null)
{
MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
CleanupAttributeFullName, false);
if (methods == null || methods.Length == 0)
{
return;
}
Reflect.InvokeMethod(methods[0], _CurrentFixture);
}
}
}
但这是最棘手的部分:该addin必须被放置在 addins
目录旁边的呢亚军。我是旁边的呢亚军TestDriven.NET 目录:
C:\Program Files\TestDriven.NET 2.0\NUnit\addins
(我创造的 addins
目录,它不在那儿)
编辑 另一件事是清除方法需要 static
!
我砍死在一起的一个简单的马吉德,你可以下载源 我的网盘.你将不得不增加引用 nunit.framework.dll
, nunit.core.dll
和 nunit.core.interfaces.dll
在适当的地方。
几点注意事项:属性类可以在任何地方放置在你的代码。我不想把它放在同一会作为addin本身,因为它引用两个 Core
关组件,所以我把它放在一个不同的组件。只记得改变行 CleanAddin.cs
, 如果你决定要把它放其他地方。
希望这有所帮助。
其他提示
由于2.5.7版本,NUnit的允许拆卸,以检测是否最后测试失败。 一种新的TestContext类允许测试访问关于他们自己的信息,包括TestStauts。
有关详情,请参阅 http://nunit.org/?p=releaseNotes&r = 2.5.7
[TearDown]
public void TearDown()
{
if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
{
PerformCleanUpFromTest();
}
}
虽然有可能强迫NUnit的成这样是不是最明智的设计,你总是可以设置临时文件的地方,如果该文件存在,运行清理。
我建议改变你的代码,以便您已经启用了数据库事务,并在测试结束时,只需要将其还原数据库到原来的状态(例如丢弃代表您的单元测试的交易)。
是,有。可以使用的 拆卸属性强>其中每次测试后,将拆毁。你要应用数据库“复位”,你必须和拆卸和重新安装前和每次测试后,脚本
此属性内的使用 的TestFixture提供一组通用的 被后执行的功能 每个测试方法被运行。
更新:根据的评论和更新的问题,我说你可以使用拆卸属性和使用私有变量,以表明该方法的内容是否应该解雇。
不过,我还没有看到你不希望任何复杂的逻辑或错误处理代码。
鉴于这种情况,我认为一个标准设置/ 拆卸一>将工作最适合你。如果有错误,你不必有任何的错误处理代码没关系。
如果您需要特殊的清理,因为接下来的测试取决于当前测试的成功完成,我建议重新审视你的测试 - 他们可能不应该是互相依赖的。
有关使用try-catch块,重新抛出捕捉到的异常什么?
try
{
//Some assertion
}
catch
{
CleanUpMethod();
throw;
}
我不喜欢PHSR建议现在,当你能负担得起,重构测试,让他们永远不必依赖于相同的数据的另一个测试需求,甚至更好的抽象的数据访问层和模拟结果来自何处该数据库。这听起来像你的测试是相当昂贵的,你,你应该做你的装配数据库和业务逻辑,你真的不关心结果被返回是什么,你的所有查询逻辑。
您还可以测试你的ExceptionHandling好多了。
另一种选择是有一个特殊的功能,将你抛出异常,在那个说,一个出现异常的的TestFixture设置一个开关。
public abstract class CleanOnErrorFixture
{
protected bool threwException = false;
protected void ThrowException(Exception someException)
{
threwException = true;
throw someException;
}
protected bool HasTestFailed()
{
if(threwException)
{
threwException = false; //So that this is reset after each teardown
return true;
}
return false;
}
}
然后,使用您的示例:
[TestFixture]
public class SomeFixture : CleanOnErrorFixture
{
[Test]
public void MyFailTest()
{
ThrowException(new InvalidOperationException());
}
[Test]
public void MySuccessTest()
{
Assert.That(true, Is.True);
}
[TearDown]
public void CleanUpOnError()
{
if (HasLastTestFailed()) CleanUpDatabase();
}
}
这里唯一的问题是,堆栈跟踪将导致CleanOnErrorFixture
到目前为止还没有提到的一个选项是包装测试中达到一个TransactionScope对象,因此它并不重要,会发生什么作为测试从来没有承诺任何东西到数据库。
下面的上的技术中的一些细节一>。你也许可以找到更多,如果你做单元测试和TransactionScope的搜索(虽然你是真的在做集成测试,如果你打一个DB)。我已经成功地用它在过去。
此方法简单,不需要任何清理,并确保测试隔离。
编辑 - 我刚刚注意到雷海耶斯回答也与我相似。
它是如何失败?是否有可能把它放在一试(做测试)/捕捉(破镜重圆DB)/ finally块?
或者你可以调用一个私有方法来解决它,当您检查您的故障状态。
我并不是说这是一个好主意,但它应该工作。 请记住,断言失败只是例外。也不要忘记还有运行只有一次在灯具的所有测试都运行后[TestFixtureTearDown]属性。
使用这两个事实,你可以写的东西,如设置一个标志,如果一个测试失败,检查测试夹具的标志的值推倒。
我不建议这样做,但它会工作。你是不是真的使用NUnit如预期,但你可以做到这一点。
[TestFixture]
public class Tests {
private bool testsFailed = false;
[Test]
public void ATest() {
try {
DoSomething();
Assert.AreEqual(....);
} catch {
testFailed = true;
}
}
[TestFixtureTearDown]
public void CleanUp() {
if (testsFailed) {
DoCleanup();
}
}
}
可以添加与点击一个[TearDown]
方法
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
结果
如果测试失败,以执行一些代码。