Java 如何参数化junit测试套件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22051705/
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
How to parameterize junit Test Suite
提问by Sergio
Is it possible to parameterize a TestSuite in junit 4 ?
是否可以在 junit 4 中参数化 TestSuite ?
For declaring a class as a test suite I need the annotation @RunWith(Suite.class)
, but the same annotation is also needed to declare the test as parameterized: @RunWith(Parameterized.class)
so I cannot add both to the same class.
为了将类声明为测试套件,我需要 annotation @RunWith(Suite.class)
,但也需要相同的 annotation 将测试声明为参数化:@RunWith(Parameterized.class)
所以我不能将两者都添加到同一个类中。
I found a similar questionin this site that did not help much. So far, all the examples I have found explain how to parameterize simple unit tests, not a complete test tuite.
我在这个网站上发现了一个类似的问题,但没有多大帮助。到目前为止,我找到的所有示例都解释了如何参数化简单的单元测试,而不是完整的测试教程。
回答by mikemil
I believe the basic answer is No, because as you said, the @RunsWith only take one parameter. I found a blog posting that got a bit creativein how to handle this situation.
我相信基本的答案是否定的,因为正如你所说,@RunsWith 只接受一个参数。我发现一篇博客文章在如何处理这种情况方面有点创意。
We don't use the parameterized tests, but may you could create a separate suite like we do that only lists the test classes and the parameterized test could be part of that. I modified our test suite to include a parameterized test class to part of the suite and it ran fine. We create our suite like below where PrimeNumberCheckerTest was a simple I pulled from the web.
我们不使用参数化测试,但您可以像我们一样创建一个单独的套件,只列出测试类,参数化测试可能是其中的一部分。我修改了我们的测试套件,将参数化测试类包含在套件的一部分中,并且运行良好。我们创建我们的套件,如下所示,其中 PrimeNumberCheckerTest 是我从网上提取的一个简单的。
package com.jda.portfolio.api.rest.server;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ com.mycompany.api.rest.server.resource.TestCartResourceJava.class,
com.mycompany.api.rest.server.resource.TestCustomerResource.class,
com.mycompany.api.rest.server.resource.TestWizardProfileResource.class,
com.mycompany.api.rest.server.interceptor.TestBaseSearchInterceptor.class,
com.mycompany.api.rest.server.resource.TestQueryParameters.class,
com.mycompany.api.rest.server.expression.TestCartExpressionGenerator.class,
com.mycompany.api.rest.server.expression.TestPreferenceExpressionGenerator.class,
com.mycompany.api.rest.server.PrimeNumberCheckerTest.class,
})
public class AllTests {}
Here's the source for the parameterized test case;
这是参数化测试用例的来源;
package com.jda.portfolio.api.rest.server:
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Parameterized.class)
@SuiteClasses({PrimeNumberCheckerTest.class})
public class PrimeNumberCheckerTest {
private Integer inputNumber;
private Boolean expectedResult;
private PrimeNumberChecker primeNumberChecker;
@Before
public void initialize() {
primeNumberChecker = new PrimeNumberChecker();
}
// Each parameter should be placed as an argument here
// Every time runner triggers, it will pass the arguments
// from parameters we defined in primeNumbers() method
public PrimeNumberCheckerTest(Integer inputNumber,
Boolean expectedResult) {
this.inputNumber = inputNumber;
this.expectedResult = expectedResult;
}
@Parameterized.Parameters
public static Collection primeNumbers() {
return Arrays.asList(new Object[][] {
{ 2, true },
{ 6, false },
{ 19, true },
{ 22, false },
{ 23, true }
});
}
// This test will run five times since we have as many parameters defined
@Test
public void testPrimeNumberChecker() {
System.out.println("Parameterized Number is : " + inputNumber);
assertEquals(expectedResult,
primeNumberChecker.validate(inputNumber));
}
回答by Paul Hicks
I agree, it's not possible with the provided classes, but there are workarounds that will get you most of the way there, like @mikemil's.
我同意,提供的类是不可能的,但是有一些解决方法可以让你大部分时间都在那里,比如@mikemil。
I've spent some time extending Suite and delegating to Parameterized, with partial success; it is possible to build runner that does what you want, and the code is more-or-less written for you in those two classes. The way those classes interact (in particular, the definition of Parameterized#getChildren()
) makes it difficult to extend or delegate to those classes to accomplish what you need, but creating a whole new class than extends ParentRunner
and lifts code from the other two would be fairly easy.
我花了一些时间扩展 Suite 并委托给 Parameterized,取得了部分成功;可以构建执行您想要的运行程序,并且在这两个类中或多或少地为您编写了代码。这些类交互的方式(特别是 的定义Parameterized#getChildren()
)使得扩展或委托给这些类来完成您需要的事情变得困难,但是创建一个全新的类而不是ParentRunner
从其他两个类中扩展和提升代码会相当容易。
I'll try to get more time to come back to this later. If you do build a new runner before I get around to it, please post it as an answer, I'd love to use it myself.
稍后我会争取更多时间来讨论这个问题。如果您确实在我开始使用它之前构建了一个新的跑步者,请将其作为答案发布,我很乐意自己使用它。
回答by Alicia
I was able to parameterize a test suite and use its data in a test class member of the suite as follows:
我能够参数化测试套件并在套件的测试类成员中使用其数据,如下所示:
In JUTsuite:
在 JUTsuite 中:
@RunWith(Suite.class)
@Suite.SuiteClasses({
JUT_test1.class,
})
public class JUTSuite{
// Declare all variables/objects you want to share with the test classes, e.g.
protected static List<Fx> globalFxs;
// This is the data list we'll use as parameters
protected static List<Dx> globalDxs;
@Parameters
public static Collection<Object[]> data(){
// Instantiate object list for parameters.
// Note: you must do it here and not in, say, @BeforeClass setup()
// e.g.
globalDxs=new ArrayList<Dx>(serverObj.values());
Collection<Object[]> rows=new ArrayList<Object[]>();
for(Dx d:globalDxs) {
rows.add(new Object[]{d});
}
return rows;
}
@BeforeClass
public static void setUp() throws Exception {
// Instantiate/initialize all suite variables/objects to be shares with test classes
// e.g. globalFxs=new ArrayList<Fx>();
}
@AfterClass
public static void tearDown() throws Exception {
// Clean up....
}
}
Next, in test class:
接下来,在测试类中:
@RunWith(Parameterized.class)
public class JUT_test1 {
// declare local names (if desired) for suite-wide variable/objects
// e.g.
private static List<Fx> globalFxs;
// This is the test parameter:
private Dx d;
public JUT_test1(Dx d){
this.d=d;
}
@Parameters
public static Collection<Object[]> data(){
// Note: we're calling the suite's data() method which has already executed.
return JUTSuite.data();
}
@BeforeClass
public static void setUpBeforeClass() throws Exception {
// (If desired)initialize local variables by referencing suite variables.
// e.g.globalFxs=JUTSuite.globalFxs;
}
}
回答by Peter Wippermann
You're right: Both Suite
and Parameterized
are Runners and only one Runner
may be used to run a test at a time. Standard JUnit 4 doesn't provide a combined Runner.
您是对的:Suite
和Parameterized
都是 Runners,并且一次只能使用一个Runner
来运行测试。标准 JUnit 4 不提供组合的 Runner。
You can either implement your own Runner or have a look at this ready-to-use library which provides a ParameterizedSuite
Runner: https://github.com/PeterWippermann/parameterized-suite
您可以实现自己的 Runner 或查看这个提供ParameterizedSuite
Runner 的即用型库:https: //github.com/PeterWippermann/parameterized-suite
A parameterized test suite looks like this:
参数化测试套件如下所示:
@RunWith(ParameterizedSuite.class)
@SuiteClasses({OneTest.class, TwoTest.class})
public class MyParameterizedTestSuite {
@Parameters(name = "Parameters are {0} and {1}")
public static Object[] params() {
return new Object[][] {{'A',1}, {'B',2}, {'C',3}};
}
回答by Shantonu
the best solution will be, keep suit classes separately in a blank class. For example, I am testing logins as Parameterized tests and putting in a suit (for navigation performance measurement)
最好的解决方案是,将西装类单独保存在一个空白类中。例如,我正在测试登录作为参数化测试并穿上西装(用于导航性能测量)
@RunWith(Suite.class)
@Suite.SuiteClasses({
LoginPageTest.class,
HomePageTests.class})
public class PerformanceTests {
}
and LoginPageTest is actually Parameterizedtests
而 LoginPageTest 实际上是 Parameterizedtests
@RunWith(Parameterized.class)
public class LoginPageTest
{...}
回答by Markus Mitterauer
As already stated multiple times, it's not possible to parameterize a test suite with the runners provided by JUnit 4
.
正如已经多次说明的那样,不可能使用JUnit 4
.
Anyway, I wouldn't recommend to make your testclasses dependent from some externally provided state. What if you want to run a single testclass?
无论如何,我不建议让您的测试类依赖于某些外部提供的状态。如果您想运行单个测试类怎么办?
I would recommend to make your separate test classes @Parameterized
and use a utility class to provide the parameters:
我建议制作单独的测试类@Parameterized
并使用实用程序类来提供参数:
@RunWith(Suite.class)
@SuiteClasses({ Test1.class, Test2.class })
public class TestSuite {
// suite
}
@RunWith(Parameterized.class}
public class Test1 {
public Test1(Object param1) { /* ... */ }
@Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
@Test
public void someTest() { /* ... */ }
}
@RunWith(Parameterized.class}
public class Test2 {
public Test2(Object param1) { /* ... */ }
@Parameters
public static Collection<Object[]> data() {
return TestParameters.provideTestData()
}
@Test
public void someOtherTest() { /* ... */ }
}
class TestParameters {
public static Collection<Object[]> provideTestData() {
Collection<Object[]> data = new ...;
// build testdata
return data;
}
回答by allofmex
Maybe this answer helps: Parameterized unit test suites
也许这个答案有帮助:参数化单元测试套件
It uses @RunWith(Enclosed.class)
and seems to solve the problem.
它使用@RunWith(Enclosed.class)
并似乎解决了问题。