mockito模拟带参数的构造函数
我有一个类如下:
public class A { public A(String test) { bla bla bla } public String check() { bla bla bla } }
构造函数A(String test)
和check()
中的逻辑是我试图模拟的东西。 我想要任何电话,如: new A($$$any string$$$).check()
返回一个虚拟的string“testing”。
我试过了:
A a = mock(A.class); when(a.check()).thenReturn("test"); String test = a.check(); // to this point, everything works. test shows as "tests" whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk); // also tried: //whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk); new A("random string").check(); // this doesn't work
但它似乎并没有工作。 new A($$$any string$$$).check()
仍然通过构造函数逻辑,而不是获取A的模拟对象。
您发布的代码适用于最新版本的Mockito和Powermockito。 也许你没有准备好A? 尝试这个:
A.java
public class A { private final String test; public A(String test) { this.test = test; } public String check() { return "checked " + this.test; } }
MockA.java
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.junit.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; @RunWith(PowerMockRunner.class) @PrepareForTest(A.class) public class MockA { @Test public void test_not_mocked() throws Throwable { assertThat(new A("random string").check(), equalTo("checked random string")); } @Test public void test_mocked() throws Throwable { A a = mock(A.class); when(a.check()).thenReturn("test"); PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a); assertThat(new A("random string").check(), equalTo("test")); } }
这两个testing都应该通过mockito 1.9.0,powermockito 1.4.12和junit 4.8.2
据我所知,你不能用mockito模拟构造函数,只能使用方法。 但根据Mockito的谷歌代码页上的wiki,有一种方法可以通过在类中创build一个返回该类的新实例的方法来模拟构造函数的行为。 那么你可以嘲笑这种方法。 以下是直接来自Mockito wiki的摘录 :
模式1 – 使用单线方法创build对象
要使用模式1(testing一个名为MyClass的类),可以replace类似的调用
Foo foo = new Foo( a, b, c );
同
Foo foo = makeFoo( a, b, c );
并写一个单行的方法
Foo makeFoo( A a, B b, C c ) { return new Foo( a, b, c ); }
在方法中不包含任何逻辑是很重要的。 只是创build对象的一行。 原因是这个方法本身不会被unit testing。
当你来testing这个类的时候,你testing的这个对象实际上是一个Mockito间谍,这个方法被覆盖,返回一个模拟。 因此,你正在testing的不是这个类本身,而是它的一个非常微小的修改版本。
你的testing类可能包含类似的成员
@Mock private Foo mockFoo; private MyClass toTest = spy(new MyClass());
最后,在你的testing方法中,你可以用类似的方法来模拟makeFoo的调用
doReturn( mockFoo ) .when( toTest ) .makeFoo( any( A.class ), any( B.class ), any( C.class ));
如果要检查传递给构造函数的参数,可以使用比任何()更具体的匹配器。
如果你只是想返回你的class级的嘲弄的对象,我认为这应该为你工作。 无论如何,你可以在这里阅读更多关于模仿对象创build的知识:
没有使用Powermock ….看到下面的例子基于本Glasser答案,因为它花了我一些时间来弄清楚..hope节省了一些时间…
原始类:
public class AClazz { public void updateObject(CClazz cClazzObj) { log.debug("Bundler set."); cClazzObj.setBundler(new BClazz(cClazzObj, 10)); } }
修改后的类:
@Slf4j public class AClazz { public void updateObject(CClazz cClazzObj) { log.debug("Bundler set."); cClazzObj.setBundler(getBObject(cClazzObj, 10)); } protected BClazz getBObject(CClazz cClazzObj, int i) { return new BClazz(cClazzObj, 10); } }
testing类
public class AClazzTest { @InjectMocks @Spy private AClazz aClazzObj; @Mock private CClazz cClazzObj; @Mock private BClazz bClassObj; @Before public void setUp() throws Exception { Mockito.doReturn(bClassObj) .when(aClazzObj) .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt()); } @Test public void testConfigStrategy() { aClazzObj.updateObject(cClazzObj); Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj); } }
Mockito有限制testing最终的,静态的和私有的方法。
有了jMockittesting库,你可以做很less的事情,非常简单和直接,如下所示:
一个java.io.File类的模拟构造函数:
new MockUp<File>(){ @Mock public void $init(String pathname){ System.out.println(pathname); // or do whatever you want } };
- 公共构造函数名称应该用$ initreplace
- 抛出的参数和exception保持不变
- 返回types应该被定义为void
模拟一个静态方法:
- 从方法模拟签名中移除静态
- 否则方法签名保持不变