使用Mockito和PowerMockito模拟类对象

问题描述 投票:5回答:4

是否可以使用Mockito和/或PowerMockito模拟类对象?

就像是:

Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
java junit mockito powermock
4个回答
2
投票

模拟Class的替代方法可能是使用Factory。我知道你担心重构,但这可以在不改变类的公共API的情况下完成。您没有提供太多代码来理解您要测试的类,但这里是一个重构的示例而不更改API。这是一个微不足道的课程,但它可能会给你一个想法。

public class Instantiator {

  public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
    return runnableClass.newInstance();
  }
}

当然,测试这个简单类的最简单的方法是使用一个真正的Runnable类,但如果你试图模拟Class,你会遇到你遇到的问题。所以,你可以这样重构它:

public class PassThruFactory {
  public Object newInstance(Class<?> clazz) throws Exception {
    return clazz.newInstance();
  }
}

public class Instantiator {
  private PassThruFactory factory = new PassThruFactory();

  public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
    return (Runnable)factory.newInstance(runnableClass);
  }
}

现在,Instantiator使用相同的公共API完成了它之前所做的(非常简单)的事情,并且不需要该类的任何客户端进行任何特殊的注入。但是,如果你想模拟工厂类并注入它,那很容易做到。


2
投票

为什么不使用代理如果你不能重构代码就没有很多选项,正如@jherics所提到的,java系统类是由引导类加载器加载的,而powermock不能重新定义它们的字节码。

但是Powermock现在与代理程序一起使用,这将允许系统类模拟。检查here以获得完整的解释。

主要思想是修改你的java命令并添加:

-javaagent: path/to/powermock-module-javaagent-1.4.12.jar

这个代理正在做的基本事情是对类进行definalize,以允许将来在特定测试中进行模拟,这就是为什么你需要使用特定类型与代理进行通信的原因,例如使用JUnit:

@Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar

TestNG也受支持。请查看wiki page了解更多信息。

希望有所帮助。


2
投票

首先,如评论中所述,您需要:

Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);

但由于PowerMock的限制,这不会以通常的方式工作。您不能简单地从java.lang,java.net,java.io或其他系统类中模拟类,因为它们是由Java的引导类加载器加载的,并且不能由PowerMock的类加载器进行字节代码操作。 (参见PowerMock FAQ#4。)从PowerMock 1.2.5开始,你可以解决这个问题。如果您要测试的课程是这样的:

public class ClassToTest {
  private Class<Runnable> runnableClass;

  public void setRunnableClass(Class<Runnable> runnableClass) {
    this.runnableClass = runnableClass;
  }

  public Runnable foo() {
    return runnableClass.newInstance();
  }
}

然后你会这样做:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {

  @Test
  public void testFoo() throws Exception {
    Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
    Runnable mockRunnable = mock(Runnable.class);

    ClassToTest objectUT = new ClassToTest();
    objectUT.setRunnableClass(mockClass);

    when(mockClass.newInstance()).thenReturn(mockRunnable);
    assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
  }
}

0
投票

这个怎么样。在类PCService中创建一个具有Object(MS)的get方法,然后模拟它。

public class PCService implements PCServiceIf {
    public MSIf getMS() {
        return ms;
    }

    private MSIf ms = new MS();
    public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId)  {
        return  getMS().getPCL(movieId);
    }
}


@Test
public void testIsMovieAccessibleToMyLevelMock()  {
    msMock = mock(MS.class);
    spy  = spy(new PCService());

    doReturn(msMock).when(spy).getMS();
    when(msMock.getPCL(movieId)).thenReturn(value);
    when(spy.getMS().getPCL(movieId)).thenReturn(value);
    assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}
© www.soinside.com 2019 - 2024. All rights reserved.