簡體   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