简体   繁体   English

强制JUnit一次运行一个测试用例

[英]Force JUnit to run one test case at a time

I have a problematic situation with some quite advanced unit tests (using PowerMock for mocking and JUnit 4.5). 我在使用一些相当高级的单元测试时遇到了问题(使用PowerMock进行模拟和JUnit 4.5)。 Without going into too much detail, the first test case of a test class will always succeed, but any following test cases in the same test class fails. 无需赘述,测试类的第一个测试用例将始终成功,但是同一测试类中的所有后续测试用例都将失败。 However, if I select to only run test case 5 out of 10, for example, it will pass. 但是,例如,如果我选择只运行10个测试用例中的5个,它将通过。 So all tests pass when being run individually. 因此,所有测试在单独运行时都会通过。 Is there any way to force JUnit to run one test case at a time? 有什么方法可以强制JUnit一次运行一个测试用例? I call JUnit from an ant-script. 我从蚂蚁脚本中调用JUnit。

I am aware of the problem of dependant test cases, but I can't pinpoint why this is. 我知道相关测试用例的问题,但是我无法查明原因。 There are no saved variables across the test cases, so nothing to do at @Before annotation. 在测试用例中没有保存的变量,因此@Before注释无需执行任何操作。 That's why I'm looking for an emergency solution like forcing JUnit to run tests individually. 这就是为什么我要寻找一种紧急解决方案,例如强制JUnit单独运行测试。

I am aware of all the recommendations, but to finally answer your question here is a simple way to achieve what you want. 我知道所有建议,但是在这里最终回答您的问题是实现所需目标的简单方法。 Just put this code inside your test case: 只需将以下代码放入您的测试用例中:

Lock sequential = new ReentrantLock();

@Override
protected void setUp() throws Exception {
    super.setUp();
    sequential.lock();
}

@Override
protected void tearDown() throws Exception {
    sequential.unlock();
    super.tearDown();
}

With this, no test can start until the lock is acquired, and only one lock can be acquired at a time. 如此一来,在获取锁之前,无法开始任何测试,并且一次只能获取一个锁。

It seems that your test cases are dependent, that is: the execution of case-X affects the execution of case-Y. 看来您的测试用例是相关的,即:case-X的执行会影响case-Y的执行。 Such a testing system should be avoided (for instance: there's no guarantee on the order at which JUnit will run your cases). 应该避免使用这样的测试系统(例如:无法保证JUnit运行案例的顺序)。

You should refactor your cases to make them independent of each other. 您应该重构案例以使它们彼此独立。 Many times the use of @Before and @After methods can help you untangle such dependencies. 很多时候使用@Before和@After方法可以帮助您解开此类依赖关系。

Your problem is not that JUnit runs all the tests at once, you problem is that you don't see why a test fails. 你的问题不在于JUnit的运行所有测试一次,你的问题是,你不明白为什么一个测试失败。 Solutions: 解决方案:

  1. Add more asserts to the tests to make sure that every variable actually contains what you think 在测试中添加更多断言,以确保每个变量实际上都包含您的想法
  2. Download an IDE from the Internet and use the built-in debugger to look at the various variables 从Internet下载IDE,然后使用内置的调试器查看各种变量
  3. Dump the state of your objects just before the point where the test fails. 在测试失败之前转储对象的状态。
  4. Use the "message" part of the asserts to output more information why it fails (see below) 使用断言的“消息”部分输出更多有关失败原因的信息(请参见下文)
  5. Disable all but a handful of tests (in JUnit 3: replace all strings "void test" with "void dtest" in your source; in JUnit 4: Replace "@Test" with "//D@TEST"). 禁用除少数测试外的所有测试(在JUnit 3中:将源中的所有字符串“ void test”替换为“ void dtest”;在JUnit 4中:将“ @Test”替换为“ // D @ TEST”)。

Example: 例:

assertEquals(list.toString(), 5, list.size());

Congratulations. 恭喜你 You have found a bug. 您发现了一个错误。 ;-) ;-)

If the tests "shouldn't" effect each other, then you may have uncovered a situation where your code can enter a broken state. 如果测试“不应该”相互影响,那么您可能已经发现了您的代码可能进入损坏状态的情况。 Try adding asserts and logging to figure out where the code goes wrong. 尝试添加断言并记录日志以找出代码出了问题的地方。 You may even need to run the tests in a debugger and check your code's internal values after the first test. 您甚至可能需要在调试器中运行测试,并在第一次测试后检查代码的内部值。

Excuse me if I dont answer your question directly, but isn't your problem exactly what TestCase.setUp() and TestCase.tearDown() are supposed to solve? 对不起,如果我没有直接回答您的问题,那么您的问题难道不是TestCase.setUp()和TestCase.tearDown()应该解决的问题吗? These are methods that the JUnit framework will always call before and after each test case, and are typically used to ensure you begin each test case in the same state. 这些方法是JUnit框架始终在每个测试用例之前和之后调用的方法,通常用于确保您以相同状态开始每个测试用例。

See also the JavaDoc for TestCase. 另请参阅JavaDoc for TestCase。

You should check your whole codebase that there are no static variables which refer to mutable state. 您应该检查整个代码库,以确保没有引用可变状态的静态变量。 Ideally the program should have no static mutable state (or at least they should be documented like I did here ). 理想情况下,程序应该没有静态可变状态(或者至少应该像我在此处那样对其进行记录)。 Also you should be very careful about cleaning up what you write, if the tests write to the file system or database. 另外,如果测试写入文件系统或数据库,则在清理所写内容时也应该非常小心。 Otherwise running the tests may leak some side-effects, which makes it hard to make the tests independent and repeatable. 否则,运行测试可能会泄漏一些副作用,这使得很难使测试独立且可重复。

Maven and Ant contain a "forkmode" parameter for running JUnit tests, which specifies whether each test class gets its own JVM or all tests are run in the same JVM. Maven和Ant包含一个用于运行JUnit测试的“ forkmode”参数,该参数指定每个测试类获得自己的JVM还是所有测试都在同一JVM中运行。 But they do not have an option for running each test method in its own JVM. 但是他们没有选择在自己的JVM中运行每个测试方法的选项。

Your description shows me, that your unit tests depend each other. 您的描述告诉我,您的单元测试是相互依赖的。 That is strongly not recommended in unit tests. 在单元测试中强烈建议不要这样做。

Unit test must be independent and isolated. 单元测试必须独立且隔离。 You have to be able to execute them alone, all of them (in which order, it does not matter). 您必须能够单独执行所有命令(顺序无关紧要)。

I know, that does not help you. 我知道,这对您没有帮助。 The problem will be in your @BeforeClass or @Before statements. 问题将出在您的@BeforeClass@Before语句中。 There will be dependencies. 会有依赖关系。 So refactor them and try to isolate the problem. 因此,重构它们并尝试找出问题所在。

Probably your mocks are created in your @BeforeClass . 可能在@BeforeClass中创建了您的@BeforeClass Consider to put it into the @Before statement. 考虑将其放入@Before语句中。 So there's no instance that last longer than a test case. 因此,没有任何实例的持续时间超过测试用例的时间。

I am aware of the problem of dependant test cases, but I can't pinpoint why this is. 我知道相关测试用例的问题,但是我无法查明原因。 There are no saved variables across the test cases, so nothing to do at @Before annotation. 在测试用例中没有保存的变量,因此@Before注释无需执行任何操作。 That's why I'm looking for an emergency solution like forcing JUnit to run tests individually. 这就是为什么我要寻找一种紧急解决方案,例如强制JUnit单独运行测试。

The @Before statement is harmless, because it is called for every test case. @Before语句是无害的,因为对于每个测试用例都会调用它。 The @Before Class is dangerous, because it has to be static. @Before 很危险,因为它必须是静态的。

It sounds to me that perhaps it isn't that you are not setting up or tearing down your tests properly (although additional setup/teardown may be part of the solution), but that perhaps you have shared state in your code that you are not aware of. 在我看来,这可能不是您没有正确设置或拆除测试(尽管解决方案中可能包含其他设置/拆卸),但也许您在代码中共享了状态,但并非如此意识到。 If an early test is setting a static / singleton / shared variable that you are unaware of, the later tests will fail if they are not expecting this. 如果早期测试设置了您不知道的静态/单例/共享变量,则后期测试如果不希望这样做会失败。 Even with Mocks this is very possible. 即使使用Mocks,这也是很有可能的。 You need to find this cause. 您需要找到此原因。 I agree with the other answers in that your tests have exposed a problem that should not be solved by trying to run the tests differently. 我同意其他答案,因为您的测试暴露了一个问题,通过尝试以不同方式运行测试不应解决该问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM