繁体   English   中英

带有@RunWith(PowerMockRunner.class)批注的测试类在扩展另一个类时两次运行测试用例

[英]Test Class with @RunWith(PowerMockRunner.class) annotation runs test cases twice when extending another class

我正在进行单元测试。 我们的项目正在与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。 当通过play“ test-only”命令运行TestClass时,返回以下输出:

[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全新安装或播放测试以运行整个测试套件时,这些测试也会运行两次。 任何可能的解决方案或建议,将不胜感激。 非常感谢大家的帮助。

建议的解决方案#1 :注入UnitTestHarness

通过使用MockitoAnnotations.initMocks(this),我能够使它们不再运行两次。 而不是您提到的注释。 当您使用注释时,测试仍将运行两次。 我尝试使用所描述的这种方法,但是在使用注释和不使用注释的情况下都遇到了各种问题。

1)这似乎不是@InjectMocks的正确使用。 我已经使用了该批注,并且当您想将要注入到具有该类型字段的另一个对象中的字段模拟出来时,它实际上是要使用的。

2)我发现,以这种方式注入时,来自UnitTestHarness的模拟行为不会转移。 我们的单元测试工具会设置一个当前的Http.Context,这不会转移到我们的测试用例中。 实际上,很多使UnitTestHarness有用的初始化都需要转移到TestClass本身的@Before方法中,这违背了我最初认为使用线束的目的。

3)我们必须将线束中拥有和使用的所有方法公开,以实现可访问性,并且必须通过线束实例或TestClass本身中的静态调用对其进行访问。 我们还需要公开线束中的字段,或者为其中大多数创建变量。

总的来说,我认为这不是解决我们所遇到问题的好方法,但我感谢您的想法。

您是否尝试使用注解@InjectMocks将UnitTestHarness注入TestClass并在@Before注释的方法中调用所有必需的方法? 请记住,在使用@InjectMocks时,还需要在类名称@RunWith(MockitoJUnitRunner.class)之上添加。 这里有一些例子。

避免继承始终是一个不错的选择。

编辑:

在我看来,问题不在图书馆。 我写了一些代码,一切正常:

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

没有这个问题的更广泛的上下文,很难建议更具体的东西,也许您应该添加更多在此类内部的代码?

暂无
暂无

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

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