我正在进行单元测试。我们的项目正在与Play合作!框架。单元测试用Java编写。我们的团队遇到了一个问题,我们遇到了测试类的重复测试运行,这些测试类使用@RunWith(PowerMockRunner.class)进行注释并扩展另一个类。
我们对测试类的主要设置如下:
单元测试工具: 包含各种测试用例之间共享的功能。还包含常用字段。
@Ignore
@RunWith(PowerMockRunner.class)
@PrepareForTest(SomeStaticClass.class)
public abstract class UnitTestHarness {
//Bunch of setup code...
}
测试类: 包含我们正在测试的类的测试用例。
public class TestClass extends UnitTestHarness {
@Test
public void testSomething(){
//Perform some tests...
}
}
如您所见,TestClass扩展了具有注释的UnitTestHarness。当PlayClass由play“test-only”命令运行时,将返回以下输出:
[info] somepackage.TestClass
[info] + testSomething
[info]
[info]
[info] Total for test somepackage.TestClass
[info] Finished in 0.055 seconds
[info] 1 tests, 0 failures, 0 errors
[info] somepackage.TestClass
[info] + testSomething
[info]
[info]
[info] Total for test somepackage.TestClass
[info] Finished in 0.001 seconds
[info] 4 tests, 0 failures, 0 errors
[info] Passed: Total 4, Failed 0, Errors 0, Passed 4
[success] Total time: 18 s, completed Apr 16, 2014 4:19:37 PM
显然,由于某种原因,测试正在运行两次。我在网上看到@RunWith注释和扩展类存在一些问题,但我一直无法找到解决方案。我觉得值得注意的是,如果我将注释从UnitTestHarness移动到TestClass,将返回以下输出:
[info] somepackage.TestClass
[info]
[info]
[info] Total for test somepackage.TestClass
[info] Finished in 0.032 seconds
[info] 0 tests, 0 failures, 0 errors
[info] somepackage.TestClass
[info] + testSomething
[info]
[info]
[info] Total for test somepackage.TestClass
[info] Finished in 0.025 seconds
[info] 4 tests, 0 failures, 0 errors
[info] Passed: Total 4, Failed 0, Errors 0, Passed 4
[success] Total time: 13 s, completed Apr 16, 2014 4:47:28 PM
在这种情况下,我们可以看到它仍在尝试运行某种类型的测试,但它实际上并没有运行额外的4,因为UnitTestHarness没有注释。我猜这是因为在第一个例子中,注释被放置在UnitTestHarness上并且被TestClass继承,在这个例子中,只有TestClass有注释,所以测试只针对那个特定的类运行。
还有其他人看过这个问题吗?显然,我们可以通过第二种方案来应对,但是理想情况下,运行这些类的额外尝试不应该发生。这是PowerMockRunner或Play框架的问题吗?当我运行mvn clean install或play test来运行整个测试套件时,测试也会运行两次。任何可能的解决方案或建议都将非常赞赏。非常感谢你的帮助。
建议的解决方案#1 :注入UnitTestHarness
我能够通过使用MockitoAnnotations.initMocks(this)让他们不要跑两次;而不是你提到的注释。使用注释时,测试仍会运行两次。我尝试使用这种描述的方法,但是在有和没有注释的情况下遇到了各种各样的问题。
1)这似乎不正确使用@InjectMocks。我已经使用了那个注释,当你有一些模拟了你想要注入另一个具有该类型字段的对象时,它真的意味着要使用。
2)我发现UnitTestHarness的模拟行为在以这种方式注入时不会传输。我们的单元测试工具设置了一个当前的Http.Context,这不会转移到我们的测试用例。实际上,很多使UnitTestHarness变得有用的初始化需要转移到TestClass本身的@Before方法中,这样就无法在我感觉到的第一个地方使用线束。
3)我们在线束中使用和使用的所有方法都必须公开以便于访问,并且可以通过线束实例或TestClass本身中的静态调用来访问。我们还需要在线束中公开字段,或者为大多数字段创建变更器。
总的来说,我认为这不是解决我们遇到的问题的好方法,但我很感激你的想法。
答案 0 :(得分:1)
您是否尝试使用注释@InjectMocks将UnitTestHarness注入TestClass并在@Before注释的方法中调用所有必要的方法?记住,当你使用@InjectMocks时,你还需要在类名@RunWith(MockitoJUnitRunner.class)之上添加。 Here是一些例子。
避免继承总是一个不错的选择。
编辑:
在我看来,问题不在图书馆。我写了一些代码并且工作正常:
public final class ClassWithStaticMethods {
public static String returnString(){
return "Sample text";
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStaticMethods.class)
public class UnitTestHarness {
private String field1 = "field1";
private String field2 = "field2";
@Before
public void setUp() {
PowerMockito.mockStatic(ClassWithStaticMethods.class);
when(ClassWithStaticMethods.returnString()).thenReturn("This static method is mocked!");
}
public List<String> createList() {
List<String> list = Lists.newArrayList();
list.add("firstElement");
list.add("secondElement");
list.add("thirdElement");
return list;
}
public Point dummyPoint() {
return new Point(2, 3);
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public String getField2() {
return field2;
}
public void setField2(String field2) {
this.field2 = field2;
}
}
public class TestClass extends UnitTestHarness {
private List<String> list;
private Point dummyPoint;
@Before
public void setup() {
list = createList();
dummyPoint = dummyPoint();
}
@Test
public void testSomething() {
System.out.println("First test method. Value of field1 from UnitTestHarness is: " + getField1());
setField1("New value");
System.out.println("First test method. Value of field1 from UnitTestHarness is: " + getField1());
}
@Test
public void testSomethingElse() {
System.out.println("Second test method. Value of field2 from UnitTestHarness is: " + getField2());
}
@Test
public void testStaticMockMethod() {
System.out.println(ClassWithStaticMethods.returnString());
}
@Test
public void testDummyPoint() {
System.out.println(String.format("My point: %s, %s", dummyPoint.getX(), dummyPoint.getY()));
}
@Test
public void testArray() {
for (String string : list) {
System.out.println("Array element:" + string);
}
}
}
这是我的控制台输出:
Running service.TestClass
Array element:firstElement
Array element:secondElement
Array element:thirdElement
First test method. Value of field1 from UnitTestHarness is: field1
First test method. Value of field1 from UnitTestHarness is: New value
Second test method. Value of field2 from UnitTestHarness is: field2
This static method is mocked!
My point: 2.0, 3.0
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.442 sec
Results :
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
如果没有这个问题的更广泛的背景,很难建议更具体的东西,也许你应该在这个类中添加更多的代码?