Java JUNIT:为大量测试类只运行一次安装程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18574513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JUNIT : run setup only once for a large number of test classes
提问by neoInfinite
I have a class, which I use as a basis for my unit tests. In this class I initialize the whole environment for my tests, setting up database mappings, enter a number of database records across multiple tables, etc. That class has a method with a @BeforeClass annotation which does the initialization. Next thing, I extend that class with specific classes in which I have @Test methods.
我有一个类,用作单元测试的基础。在这个类中,我为我的测试初始化整个环境,设置数据库映射,在多个表中输入许多数据库记录等。该类有一个带有 @BeforeClass 注释的方法,它执行初始化。接下来,我使用具有 @Test 方法的特定类扩展该类。
My question is, since the before class is exactly the same for all these test classes, how can I ensure that they are run only once for all the tests.One simple solution is that I could keep all the tests in one class. However, the number of tests is huge, also they are categorised based on functional heads. So they are located in different classes. However since they need the exact same setup, they inherit the @BeforeClass. As a result the whole setup is done at least once per test class, taking much more time in total than I would prefer.
我的问题是,由于所有这些测试类的 before 类完全相同,我如何确保它们对所有测试只运行一次。一个简单的解决方案是我可以将所有测试放在一个班级中。然而,测试的数量巨大,它们也是根据功能头进行分类的。因此,它们位于不同的类中。但是,由于它们需要完全相同的设置,因此它们继承了@BeforeClass。因此,每个测试类至少完成一次整个设置,总共花费的时间比我希望的要多得多。
I could, though, put them all in various subpackages under one package, hence if there is a way, how I can run set up once for all the tests within that package, it would be great.
但是,我可以将它们全部放在一个包下的各种子包中,因此如果有办法,我可以如何为该包中的所有测试运行一次设置,那就太好了。
回答by Aaron Digulla
JUnit doesn't support this, you will have to use the standard Java work-arounds for singletons: Move the common setup code into a static code block and then call an empty method in this class:
JUnit 不支持这一点,您将不得不对单例使用标准的 Java 解决方法:将公共设置代码移动到静态代码块中,然后在此类中调用一个空方法:
static {
...init code here...
}
public static void init() {} // Empty method to trigger the execution of the block above
Make sure that all tests call init()
, for example my putting it into a @BeforeClass
method. Or put the static code block into a shared base class.
确保所有测试都调用init()
,例如我将它放入一个@BeforeClass
方法中。或者把静态代码块放到共享基类中。
Alternatively, use a global variable:
或者,使用全局变量:
private static boolean initialize = true;
public static void init() {
if(!initialize) return;
initialize = false;
...init code here...
}
回答by Kkkev
If you can tolerate adding spring-test to your project, or you are using it already, then a good approach is to use the technique described here: How to load DBUnit test data once per case with Spring Test
如果您可以容忍将 spring-test 添加到您的项目中,或者您已经在使用它,那么一个好的方法是使用这里描述的技术:How to load DBUnit test data once per case with Spring Test
回答by skipy
Not sure if anyone still is using JUnit and trying to fix it without using Spring Runner (aka no spring integration). TestNG has this feature. But here is a JUnit based solution.
不确定是否有人仍在使用 JUnit 并尝试在不使用 Spring Runner(也就是没有 spring 集成)的情况下修复它。TestNG 有这个功能。但这是一个基于 JUnit 的解决方案。
Create a RunOnce per thread operation like so. This maintains a list of classes for which the operation has run.
像这样为每个线程操作创建一个 RunOnce。这维护了操作已运行的类的列表。
public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();
public void run(Function f) {
if (t.get() == null) {
t.set(Arrays.asList(getClass()));
f.apply(0);
} else {
if (!((List) t.get()).contains(getClass())) {
((List) t.get()).add(getClass());
f.apply(0);
}
}
}
}
Back in your unit test
回到你的单元测试
@Before
public beforeTest() {
operation.run(new Function<Integer, Void>() {
@Override
public Void apply(Integer t) {
checkBeanProperties();
return null;
}
});
}
private void checkBeanProperties() {
//I only want to check this once per class.
//Also my bean check needs instance of the class and can't be static.
}
My function interface is like this:
interface Function<I,O> {
O apply(I i);
}
When you use this way, you can perform operations once per class using ThreadLocal.
使用这种方式时,您可以使用 ThreadLocal 对每个类执行一次操作。
回答by Filip
Create one base class for all tests:
为所有测试创建一个基类:
public class BaseTest {
static{
/*** init code here ***/
}
}
and every test should inherit from it:
每个测试都应该继承它:
public class SomeTest extends BaseTest {
}
回答by FredBoutin
With JUnit4 test suite you can do something like this :
使用 JUnit4 测试套件,您可以执行以下操作:
@RunWith(Suite.class)
@Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
@BeforeClass
public static void setUp()
{
System.out.println("Runs before all tests in the annotation above.");
}
@AfterClass
public static void tearDown()
{
System.out.println("Runs after all tests in the annotation above.");
}
}
Then you run this class as you would run a normal test class and it will run all of your tests.
然后你像运行一个普通的测试类一样运行这个类,它会运行你的所有测试。
回答by fedeb
You can make one BaseTest
class with a @BeforeClass
method, then have all the other tests inherit from it. This way, when each test object is constructed, @BeforeClass
gets executed.
您可以BaseTest
使用一个@BeforeClass
方法创建一个类,然后让所有其他测试继承自它。这样,当每个测试对象被构建时,@BeforeClass
就会被执行。
Also avoid executing it just once for all the test suite, since all the test cases should be independent. @BeforeClass
should execute only once each test case, not test suite.
还要避免对所有测试套件只执行一次,因为所有测试用例都应该是独立的。@BeforeClass
每个测试用例应该只执行一次,而不是测试套件。