【问题标题】:PowerMockito returns null when mocking private method for testing public method模拟私有方法以测试公共方法时,PowerMockito 返回 null
【发布时间】:2021-09-24 13:57:50
【问题描述】:

我正在尝试编写一个比较字符串相等性的测试。

这是应该测试的类的代码sn-p

package ge.jibo.util;

public class TextManager {

  private String concatenateTwoString(String t1, String t2) {
    return t1 + t2;
  }

  public String concatenate(String t1, String t2) {
    return concatenateTwoString(t1, t2);
  }

}

这是一个测试类

package ge.jibo.util;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;

import static org.assertj.core.api.Assertions.assertThat;

public class TextManagerTest {

  @Test
  @PrepareForTest(TextManager.class)
  void checkIfConcatenationWorks() throws Exception {
    TextManager textmanager = PowerMockito.spy(new TextManager());
    PowerMockito.doReturn("someText").when(textmanager,"concatenateTwoString", Mockito.anyString(), Mockito.anyString());
    String text = textmanager.concatenate("ji","bo");
    assertThat(text).isEqualTo("jibo");
  }
}

如你所见,我想测试公共方法concatenate,它在同一个类中调用私有方法concatenateTwoString。 这个想法是我想为私有方法创建一个模拟对象,并且无论何时从公共方法调用它都应该返回常量值"someText"

但它从私有方法 concatenateTwoString 返回 null 而不是 "someText"

org.opentest4j.AssertionFailedError: 
Expecting:
 <null>
to be equal to:
 <"jibo">
but was not.
Expected :jibo
Actual   :null

有人知道如何解决吗?

依赖版本:

  1. junit-jupiter - 5.7.2
  2. junit-platform-launcher - 1.8.1
  3. 模拟核心 - 3.12.4
  4. mockito-junit-jupiter - 3.12.4
  5. powermock-core - 2.0.9
  6. powermock-api-mockito2 - 2.0.9

【问题讨论】:

    标签: unit-testing mocking mockito junit5 powermock


    【解决方案1】:

    正如@heaprc在他的帖子中提到的,“测试”方法可以正确执行,在我们使用JUnit4而不是JUnit5的情况下,并为powerMock @RunWith(PowerMockRunner.class)添加JUnit4注释。

    一切都正确,在 JUnit5 的情况下,没有直接的解决方案来模拟公共方法下的私有方法。

    那么我们有哪些选择?

    在这种情况下,在 m.o 中有三个选项:

    1. JUnit5 留给"Test framework",不要试图模拟私有方法。首先,想一想你是否真的想测试private 方法,如果有必要测试让它package-private (通过将方法更改为package-private 你打破了封装的概念,但如果你真的需要测试一下,那我觉得问题不大)
    2. 将您的"Test framework"JUnit5 降级为JUnit4。但在这种情况下,如果您已经在 JUnit5 中编写了 100 个测试,则必须将它们全部更改为在 JUnit4 上工作。你必须降级你的框架真的很烦人,你必须为 JUnit4 重写 100 个测试这一事实非常烦人。
    3. JUnit4JUnit5 一起工作。我认为这是更好的解决方案,示例如下:

    您的pom.xml 文件中必须有以下依赖项。

    pom.xml

     <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.8.1</version>
        </dependency>
    
    
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>2.0.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito2</artifactId>
            <version>2.0.9</version>
            <scope>test</scope>
        </dependency>
    
    • junit-vintage-engine 允许您运行 JUnit4 测试。
    • junit-jupiter-engine 允许您运行 JUnit5 测试。

    代码 sn-p

        import org.junit.Assert;
        import org.junit.jupiter.api.Assertions;
        import org.junit.jupiter.api.Test;
        import org.junit.runner.RunWith;
        import org.mockito.Mockito;
        import org.powermock.api.mockito.PowerMockito;
        import org.powermock.core.classloader.annotations.PrepareForTest;
        import org.powermock.modules.junit4.PowerMockRunner;
        
        @PrepareForTest(TextManager.class)
        @RunWith(PowerMockRunner.class)
        public class TextManagerTest {
        
            @org.junit.Test  //Test using Junit4
            public void checkIfConcatenationWorksWithJunit4() throws Exception {
                TextManager textmanager = PowerMockito.spy(new TextManager());
                PowerMockito.doReturn("jibo").when(textmanager, "concatenateTwoString", Mockito.anyString(), Mockito.anyString());
                String text = textmanager.concatenate("ji", "bo");
                Assert.assertEquals(text,"jibo");
            }
        
            @Test  //Test using Junit5
            public void checkIfConcatenationWorksWithJunit5() {
                Assertions.assertEquals("text","jibo");
            }
        }
    

    在这种情况下,您将使用Junit4 平台运行checkIfConcatenationWorksWithJunit4 测试方法,@RunWith(PowerMockRunner.class) 将用于此执行。 在checkIfConcatenationWorksWithJunit5方法的情况下,它将运行在Junit5(Jupiter)平台上。

    终于

    您必须在pom.xml 文件中添加maven-surefire-plugin 以使JUnit4JUnit5 测试在构建它或使用maven commands 进行测试时进行测试。

       <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                </plugin>
            </plugins>
        </build>
    

    在不添加maven-surefire-plugin 的情况下,只有一个平台(JUnit4) 测试将在运行时执行。

    【讨论】:

      【解决方案2】:

      您忘记添加@RunWith 并指定PowerMockRunner

      如果您能够使用 Junit-4,这就是解决方案。

      @RunWith(PowerMockRunner.class)
      @PrepareForTest(TextManager.class)
      public class TextManagerTest {
      
        @Test
        public void checkIfConcatenationWorks() throws Exception {
          // Arrange
          TextManager textmanager = PowerMockito.spy(new TextManager());
          PowerMockito.doReturn("someText").when(textmanager,"concatenateTwoString"
          , Mockito.anyString()
          , Mockito.anyString());
      
          // Act
          String text = textmanager.concatenate("ji","bo");
      
          // Assert
          assertThat(text).isEqualTo("jibo");
        }
      }
      

      【讨论】:

      • 我添加了@RunWith注解但没有任何改变。
      • 如果我将“concatenateTwoString”方法从私有更改为包私有,那么它可以完美运行。无法理解原因。
      • RunWith 和 Jupiter 不能同时使用。
      • @heaprc 您的建议添加“@RunWith(PowerMockRunner.class)”注释适用于junit4,但您如何解决Junit5 的问题?
      猜你喜欢
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 2014-09-21
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      相关资源
      最近更新 更多