如何忽略 NUnit 中基于另一个测试的测试?

发布于 2024-08-12 03:21:07 字数 1202 浏览 4 评论 0原文

我正在为数据库操作编写一些 NUnit 测试。显然,如果Add()失败,那么Get()也会失败。但是,当 Add()Get() 都失败时,它看起来具有欺骗性,因为看起来有两个问题,而不是只有一个问题。

有没有办法指定测试运行的“顺序”,如果第一个测试失败,则忽略后续测试?

同样,有没有办法自己订购单元测试类?例如,我想先运行基本数据库操作的测试,然后再测试 UI 中的往返数据。

注意:这与测试相互依赖有点不同,它更像是在运行一堆测试之前确保某些东西首先工作。例如,如果您一开始无法连接到数据库,那么运行一堆数据库操作就是浪费时间。

编辑:似乎有些人没有抓住要点。我不是这样做的:

[Test]
public void AddTest()
{
    db.Add(someData);
}

[Test]
public void GetTest()
{
    db.Get(someData);
    Assert.That(data was retrieved successfully);
}

相反,我这样做的是:

[Test]
public void AddTest()
{
    db.Add(someData);
}

[Test]
public void GetTest()
{
    // need some way here to ensure that db.Add() can actually be performed successfully
    db.Add(someData);
    db.Get(somedata);
    Assert.That(data was retrieved successfully);
}

换句话说,我想确保在测试是否可以检索数据之前可以首先添加数据。人们假设我正在使用第一次测试的数据来通过第二次测试,但事实并非如此。我试图确保一项操作可能,然后再尝试另一项依赖于该操作的操作。

正如我已经说过的,您需要确保在运行数据库操作之前可以连接到数据库。或者您可以在执行文件操作之前打开文件。或者在测试 API 调用之前连接到服务器。或者……你明白了。

I'm writing some NUnit tests for database operations. Obviously, if Add() fails, then Get() will fail as well. However, it looks deceiving when both Add() and Get() fail because it looks like there's two problems instead of just one.

Is there a way to specify an 'order' for tests to run in, in that if the first test fails, the following tests are ignored?

In the same line, is there a way to order the unit test classes themselves? For example, I would like to run my tests for basic database operations first before the tests for round-tripping data from the UI.

Note: This is a little different than having tests depend on each other, it's more like ensuring that something works first before running a bunch of tests. It's a waste of time to, for example, run a bunch of database operations if you can't get a connection to the database in the first place.

Edit: It seems that some people are missing the point. I'm not doing this:

[Test]
public void AddTest()
{
    db.Add(someData);
}

[Test]
public void GetTest()
{
    db.Get(someData);
    Assert.That(data was retrieved successfully);
}

Rather, I'm doing this:

[Test]
public void AddTest()
{
    db.Add(someData);
}

[Test]
public void GetTest()
{
    // need some way here to ensure that db.Add() can actually be performed successfully
    db.Add(someData);
    db.Get(somedata);
    Assert.That(data was retrieved successfully);
}

In other words, I want to ensure that the data can be added in the first place before I can test whether it can be retrieved. People are assuming I'm using data from the first test to pass the second test when this is not the case. I'm trying to ensure that one operation is possible before attempting another that depends on it.

As I said already, you need to ensure you can get a connection to the database before running database operations. Or that you can open a file before performing file operations. Or connect to a server before testing API calls. Or...you get the point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

逆光飞翔i 2024-08-19 03:21:07

NUnit 支持“Assume.That”语法来验证设置。这被记录为理论的一部分(感谢clairestreb)。 NUnit.Framework 命名空间中有一个类 Assume。引用文档:

/// Provides static methods to express the assumptions
/// that must be met for a test to give a meaningful
/// result. If an assumption is not met, the test
/// should produce an inconclusive result.

所以在上下文中:

public void TestGet() {
    MyList sut = new MyList()
    Object expecting = new Object();
    sut.Put(expecting);
    Assume.That(sut.size(), Is(1));
    Assert.That(sut.Get(), Is(expecting));
}

NUnit supports an "Assume.That" syntax for validating setup. This is documented as part of the Theory (thanks clairestreb). In the NUnit.Framework namespace is a class Assume. To quote the documentation:

/// Provides static methods to express the assumptions
/// that must be met for a test to give a meaningful
/// result. If an assumption is not met, the test
/// should produce an inconclusive result.

So in context:

public void TestGet() {
    MyList sut = new MyList()
    Object expecting = new Object();
    sut.Put(expecting);
    Assume.That(sut.size(), Is(1));
    Assert.That(sut.Get(), Is(expecting));
}
噩梦成真你也成魔 2024-08-19 03:21:07

测试应该决不相互依赖。你刚刚发现了原因。从定义上来说,相互依赖的测试是脆弱的。如果您需要数据库中的数据来测试 Get(),请将其放在设置步骤中。

Tests should never depend on each other. You just found out why. Tests that depend on each other are fragile by definition. If you need the data in the DB for the test for Get(), put it there in the setup step.

何其悲哀 2024-08-19 03:21:07

我认为问题在于您使用 NUnit 来运行 NUnit 运行的单元测试之外的其他内容。

本质上,您希望 AddTest 在 GetTest 之前运行,并且希望 NUnit 在 AddTest 失败时停止执行测试。

问题是这与单元测试相反 - 测试应该完全独立并以任何顺序运行。

单元测试的标准概念是,如果您围绕“添加”功能进行测试,那么您可以在“获取”测试中使用“添加”功能,而不必担心“添加”在“获取”测试中是否有效。您知道“添加”有效 - 您对其进行了测试。

“第一”原则 (http://agileinaflash.blogspot.com/2009/02/ first.html)描述了单元测试的行为方式。您要编写的测试违反了“I”(隔离)和“R”(可重复)。

如果您担心两个测试之间的数据库连接丢失,我建议您的代码应该使用某种数据接口,而不是在测试期间连接到真实的数据库,并且对于测试,您应该使用一个模拟界面。如果测试的目的是练习数据库连接,那么您可能只是使用了错误的工具来完成这项工作 - 这并不是真正的单元测试。

I think the problem is that you're using NUnit to run something other than the sort of Unit Tests that NUnit was made to run.

Essentially, you want AddTest to run before GetTest, and you want NUnit to stop executing tests if AddTest fails.

The problem is that that's antithetical to unit testing - tests are supposed to be completely independent and run in any order.

The standard concept of Unit Testing is that if you have a test around the 'Add' functionality, then you can use the 'Add' functionality in the 'Get' test and not worry about if 'Add' works within the 'Get' test. You know 'Add' works - you have a test for it.

The 'FIRST' principle (http://agileinaflash.blogspot.com/2009/02/first.html) describes how Unit tests should behave. The test you want to write violates both 'I' (Isolated) and 'R' (Repeatable).

If you're concerned about the database connection dropping between your two tests, I would recommend that rather than connect to a real database during the test, your code should use some sort of a data interface, and for the test, you should be using a mock interface. If the point of the test is to exercise the database connection, then you may simply be using the wrong tool for the job - that's not really a Unit test.

夜声 2024-08-19 03:21:07

我不认为这是开箱即用的。

无论如何,您所描述的测试类设计将使测试代码非常脆弱。

I don't think that's possible out-of-box.

Anyway, your test class design as you described will make the test code very fragile.

短叹 2024-08-19 03:21:07

MbUnit 似乎有一个 DependsOnAttribute 这将允许您做您想做的事情。

如果其他测试夹具或测试
方法失败,则该测试将不会
跑步。此外,依赖性力量
这个测试要在那些之后运行
取决于。

虽然对 NUnit 一无所知。

MbUnit seems to have a DependsOnAttribute that would allow you to do what you want.

If the other test fixture or test
method fails then this test will not
run. Moreover, the dependency forces
this test to run after those it
depends upon.

Don't know anything about NUnit though.

小兔几 2024-08-19 03:21:07

您不能假定测试装置执行的任何顺序,因此必须在测试类中检查任何先决条件。

将 Add 测试分离到一个测试类(例如 AddTests)中,并将 Get 测试放入另一个测试类(例如 GetTests 类)中。

在 GetTests 类的 [TestFixtureSetUp] 方法中,检查您是否具有工作数据库访问权限(例如 Add 的工作),如果没有,则根据您认为适当的情况,Assert.Ignore 或 Inconclusive。

当不满足先决条件时,这将中止 GetTests 测试装置,并跳过尝试运行它包含的任何单元测试。
(我想!我是 nUnit 新手。)

You can't assume any order of test fixture execution, so any prerequisites have to be checked for within your test classes.

Segregate your Add test into one test-class e.g. AddTests, and put the Get test(s) into another test-class, e.g. class GetTests.

In the [TestFixtureSetUp] method of the GetTests class, check that you have working database access (e.g. that Add's work), and if not, Assert.Ignore or Inconclusive, as you deem appropriate.

This will abort the GetTests test fixture when its prerequisites aren't met, and skip trying to run any of the unit tests it contains.
(I think! I'm an nUnit newbie.)

好菇凉咱不稀罕他 2024-08-19 03:21:07

创建一个全局变量并在 Get 测试中返回,除非 Add 将其设置为 true(在 Add 的最后一行执行此操作):

public boolean addFailed = false;
public void testAdd () {
    try {
        ... old test code ...
    } catch (Throwable t) { // Catch all errors
        addFailed = true;
        throw t; // Don't forget to rethrow
    }
}
public void testGet () {
    if (addFailed) return;
    ... old test code ...
}

Create a global variable and return in the test for Get unless Add set it to true (do this in the last line of Add):

public boolean addFailed = false;
public void testAdd () {
    try {
        ... old test code ...
    } catch (Throwable t) { // Catch all errors
        addFailed = true;
        throw t; // Don't forget to rethrow
    }
}
public void testGet () {
    if (addFailed) return;
    ... old test code ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文