我试图建立一些参数化的测试套件,遗憾的是到目前为止没有任何运气。 我有两组参数,我想用所有可能的组合运行多个测试用例(它们在不同的类中)。我尝试使用JUnit4,但我无法正确设置它。这将是我的基本想法:
TestSuite1.class
设置一组参数,然后启动TestSuite2.class
。TestSuite2.class
设置第二组参数,然后启动将使用这两个参数的实际测试。 同时,似乎无法同时在Suite.class
注释中设置Parameterized.class
和RunWith
(根据谷歌,Parameterized
extends {{ 1}},如果我使用,我通常会得到“没有找到可运行的方法”消息。)
这就是我的代码基本上是这样的:
TestSuite1.class:
Suite
@RunWith(Parameterized.class)
@Parameterized.SuiteClasses({TestSuite2.class})
//I have tried with @RunWith(Suite.class) and
//@Suite.SuiteClasses({TestSuite2.class}) annotations also - all combinations
public class TestSuite1{
public TestSuite1(int number) {
Params.first = number;
}
@Parameters
public static Collection<Object[]> parameters(){
Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
return Arrays.asList(data);
}
}
看起来与TestSuite2.class
相同,只是我已将TestSuite1.class
添加到套件而非TestCase1.class
,并且它在TestSuite2
中设置了另一个变量}。
TestCase1.class:
Params
我对所有想法持开放态度 - 即使是以TestNG为例。我也试过了(虽然今天是我第一次看到它),但是我注意到套件与JUnit有点不同。我不想在测试之前设置XML文件,我想以编程方式解决所有设置。
我想用任何框架实现的目标是什么?
更新:使用TestNG,我有以下代码:
Start.class:
public class TestCase1 {
@Test
public void test1(){
System.out.println("first: "+Params.first+" second: "+Params.second);
Assert.assertTrue(true);
}
}
Params.class:
public class Start {
public static void main(String[] args){
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { FirstTest.class, SecondTest.class });
testng.addListener(tla);
testng.run();
}
}
FirstTest.class:
public class Params {
@DataProvider(name = "param")
public static Object[][] createData() {
Object[][] data = new Object[][] { { 1 }, { 2}, { 3}, { 4} };
return data;
}
}
public class FirstTest {
@Test(dataProvider = "param", dataProviderClass = Params.class)
public static void printIt(int number){
System.out.println("FirstTest: "+number);
}
}
与SecondTest.class
相同。如果我运行它,它运行FirstTest.class
4次,然后运行FirstTest
4次。我想一次运行SecondTest
,并且FirstTest
一次运行第一组参数。然后我想运行SecondTest
和FirstTest
一次,使用第二组参数等。
我尝试设置setPreserveOrder(true),并尝试了所有setParallel选项。然而,在这种情况下,结果是随机顺序。
(这将是一些硒测试。我知道测试不应该相互依赖,但仍然是我想要的方式)
答案 0 :(得分:0)
基本上,据我所知,您要做的是使用一组参数运行测试。这对于JUnit来说是可能的,这就是为什么用@Parameters注释的方法返回一个数组集合(通常是一组集合)。
看看这个例子:
import static org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class TestCase1 {
public TestCase1(int first, int second) {
Params.first = first;
Params.second = second;
}
@Parameters
public static Collection<Object[]> parameters(){
Object[][] data = new Object[][] { { 1, 11 }, { 2, 22 }, { 3, 33 }, { 4, 44 } };
return Arrays.asList(data);
}
@Test
public void test1(){
System.out.println("first: "+Params.first+" second: "+Params.second);
Assert.assertTrue(true);
}
}
编辑: 如果要在多个测试之间共享参数,可以在测试用例中使用抽象。
public class AbstractParametrizedTest {
public AbstractParametrizedTest(int first, int second) {
Params.first = first;
Params.second = second;
}
@Parameterized.Parameters
public static Collection<Object[]> parameters(){
Object[][] data = new Object[][] { { 1, 11 }, { 2, 22 }, { 3, 33 }, { 4, 44 } };
return Arrays.asList(data);
}
}
@RunWith(Parameterized.class)
public class TestCase1 extends AbstractParametrizedTest {
public TestCase1(int first, int second) {
super(first, second);
}
...
}
然而,我认为最好的方法是使用TestNGs数据提供商。请参阅5.6.2节中的示例以及静态数据提供程序的使用 http://testng.org/doc/documentation-main.html
答案 1 :(得分:0)
为了实现按顺序执行具有相同参数的所有测试用例的目标,您需要一个不同的Runner
,因为该行为保存在该类中。您很幸运,因为JUnit Toolbox Project和ParallelParameterized
课程都可以使用!
答案 2 :(得分:0)
虽然Suite
延伸Suite(Class<?>, RunnerBuilder)
,但它的行为完全不同 - 不尊重Liskov substitution principle。这是因为通常构造函数@SuiteClasses
处理Parameterized(Class<?>)
注释。但是@Parameters
会将此行为替换为Suite
。
如果要将Parameterized
和Runner
的行为结合起来,则必须在JUnit 4之外查看。您可以像another post here中提到的Adam Hawkes一样实施自己的ParameterizedSuite
。
我自己做了同样的事情并拼凑了一个图书馆,为您提供@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}};
}
亚军:https://github.com/PeterWippermann/parameterized-suite
参数化测试套件如下所示:
{{1}}
答案 3 :(得分:0)
其他一些建议似乎更灵活:@RunWith(Enclosed.class)
简而言之:
而不是@RunWith(Enclosed.class)
,只需使用@RunWith(Enclosed.class)
public class FastTest {
public static class Test1FirstAppInit extends AppInitTest { }
public static class Test2Download extends DownloadTest{ }
public static class Test3OtherTest extends OtherTest { }
}
并扩展您的测试类
@RunWith(Enclosed.class)
public class FastTest {
private static Iterable<? extends Object> mAllLocale = Arrays.asList(Locale.ENGLISH, Locale.GERMAN);
private static Iterable<? extends Object> mSingleLocale = Arrays.asList(Locale.ENGLISH);
/*
Run test class for all Locale
*/
@RunWith(Parameterized.class)
public static class Test1FirstAppInit extends AppInitTest {
@Parameterized.Parameter
public Locale mLocale;
@Parameterized.Parameters
public static Iterable<? extends Object> data() {
return mAllLocale;
}
@Override
public Locale getLocale() {
return mLocale;
}
@Override
public void test001ResetAll {
assumeTrue(false); // skip test completedly
}
@Override
public void test002ClearAppData() {
// replace existing test
if (getLocale() != Locale.ENGLISH) {
/*
should run only on first Locale
skip test on following Parameter runs
*/
assumeTrue(false); // skip test
}
else {
super.test000ClearAppData();
}
}
}
/*
Run test class only for one Locale
*/
@RunWith(Parameterized.class)
public static class Test2Download extends DownloadTest{
@Parameterized.Parameter
public Locale mLocale;
@Parameterized.Parameters
public static Iterable<? extends Object> data(){
return mSingleLocale;
}
@Override
public Locale getLocale() {
return mLocale;
}
@Override
public void test900Delete() {
assumeTrue(false); // skip test
}
}
/*
Test not Parameterized
*/
public static class Test3OtherTest extends OtherTest { }
}
现在使用参数化:
@RunWith(AndroidJUnit4.class)
@LargeTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DownloadTest {
public Locale getLocale() {
// will be overwritten in @RunWith(Enclosed.class)
// but we are still able to run test class separatedly
return Locale.ENGLISH;
}
@Test
public void test900Delete() {
....
}
....
}
参数化测试的测试类如下所示:
public class SortedEnclosed extends Suite {
public SortedEnclosed(Class<?> klass, RunnerBuilder builder) throws Throwable {
super(builder, klass, filterAbstractClasses(klass.getClasses()));
}
protected static Class<?>[] filterAbstractClasses(final Class<?>[] classes) {
final List<Class<?>> filteredList= new ArrayList<Class<?>>(classes.length);
for (final Class<?> clazz : classes) {
if (!Modifier.isAbstract(clazz.getModifiers())) {
filteredList.add(clazz);
}
}
// this is new (there may be better way with own "@FixClassOrder"...):
Collections.sort(filteredList, new Comparator<Class<?>>() {
@Override
public int compare(Class<?> o1, Class<?> o2) {
return o1.getSimpleName().compareTo(o2.getSimpleName());
}
});
//
return filteredList.toArray(new Class<?>[filteredList.size()]);
}
}
完全符合我的搜索内容。我可以创建不同的测试场景(完整测试,快速测试......)。只需创建不同的@RunWith(Enclosed.class)类并扩展您想要包含的测试。
只有侧点似乎是Enclosed.class不关心排序顺序(如果对你很重要)。 我通过替换Enclosed来解决它:
@RunWith(SortedEnclosed.class)
然后使用{{1}}