【问题标题】:JUnit: mock a method called inside another methodJUnit:模拟在另一个方法中调用的方法
【发布时间】:2020-12-08 13:11:18
【问题描述】:

假设我有一个类Tournament,其方法为register()isAlreadyRegistered()。下面是示例代码。

public class Tournament {

    private boolean register(String teamName) {

        if(!isAlreadyRegistered(teamName)) {
    
           // register team
    
           return True;
        }
        return False;
    }
    
    private boolean isAlreadyRegistered(String teamName) {
        // Check if team is already registered, involves DB calls
    }

    public static void main(String[] args) throws Exception {
        Tournament tournament = new Tournament();
        tournament.register("e-LEMON-ators");
    }
}

我有一个 Java 测试用例,它调用 Tournament 类的 main 方法,这导致调用 register() 方法和register() 方法调用isAlreadyRegistered()。考虑下面的代码:

@Test
public void testTournament() {
    try {
        Tournament.main(args);
        } catch (Exception e) {
            fail();
        }
}

我想模拟isAlreadyRegistered(),可能使用Mockito,所以它总是返回True

注意:该示例仅用于演示目的,我不能修改 Tournament 类。只能在测试用例中进行修改。单独测试register() 不是一种选择(必须通过 main 方法进行调用)

编辑:我无法为 Tournament 类创建对象,即我只能通过 main() 方法与该类交互

【问题讨论】:

  • 感谢@SusanMustafa,但我无法为Tournament 类创建对象,即我只能通过main() 方法与该类交互
  • 那么您基本上就拥有了“超级难以测试的代码”。现实世界的解决方案是更改您的生产代码。但请注意:您可以使用 PowerMock(ito),这将允许您“拦截”对 new Tournament() 的调用以返回一些模拟对象(并且您仍然可以在需要时调用真实方法的模拟)。但所有这些都是肮脏的黑暗魔法。除非你真的别无选择,否则不要这样做。

标签: java unit-testing junit mocking mockito


【解决方案1】:

尝试将实际的注册方法调用移动到不同的方法中,以便您可以将锦标赛实例传递给该方法。这意味着,将您的主要方法修改为

public static void main(String[] args) throws Exception {
    Tournament tournament = new Tournament();
    performRegister(tournament);
  }

  public static void performRegister(Tournament tournament) {
    tournament.register("e-LEMON-ators");
  }

现在你的测试方法如下。

@Test
  public void testTournament() {
    try {
      Tournament tournament = Mockito.mock(Tournament.class);
      Mockito.when(tournament.isAlreadyRegistered(anyString())).thenReturn(true);
      Tournament.performRegister(tournament);
    } catch (Exception e) {
      fail();
    }
  }

编辑: 另一种解决方案是,如果不想修改Tournament 类,请使用PowerMock

这里是测试类

    import static org.junit.Assert.fail;
    import static org.mockito.Matchers.anyString;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(Tournament.class)
    public class TournamentTest {
    
      @Test
      public void testTournament() {
        try {
          Tournament mock = PowerMockito.mock(Tournament.class);
          PowerMockito.when(mock.isAlreadyRegistered(anyString())).thenReturn(true);
          PowerMockito.whenNew(Tournament.class).withAnyArguments().thenReturn(mock);
          Tournament.main(null);
        } catch (Exception e) {
          fail();
        }
      }
    
    }

这里是依赖项

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>

这是供参考的文件
Tournament.java : https://gist.github.com/sjabiulla/4bdf71f81079e38aef137e64913bf26b TournamentTest.javahttps://gist.github.com/sjabiulla/4a557516e834bba6d6047687f7e32deb pom.xml : https://gist.github.com/sjabiulla/10abb153e82e14194fd1ccc2689b192d

【讨论】:

  • 嗨@i.am.jabi,就像我在问题中提到的那样,我无法修改Tournament 类,您的解决方案将涉及添加其他方法。
  • @ShubhamKadam 现在检查编辑的解决方案
  • 嗨@i.am.jabi,我试过你的代码,但没有用。我尝试打印isAlreadyRegistered() 返回的值,它打印了false
  • @ShubhamKadam ,我已经对此进行了测试并提供了解决方案。它在我身边 100% 有效。你能告诉我你有什么依赖项吗?在我的 pom.xml 中,我只添加了上面提到的 PowerMock 依赖项,实际上没有其他任何东西。我正在使用 Java 8。
  • 嗨@i.am.jabi,我创建了一个新项目并使用了你提到的依赖项,然后我确保isAlreadyRegistered() 抛出异常(除以零)并且确实如此,这导致测试用例失败。 PowerMockito 不应该阻止这种情况的发生吗?即返回true FYI。我也在使用 java 8 (openJDK)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多