2012-11-13 64 views
55

构造函数我有如下的类:模拟与参数

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()返回一个虚拟字符串"test"

我想:

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的模拟对象。

+0

正在你的嘲笑检查()方法吗? –

+0

@BenGlasser check()工作正常。只是whenNew看起来不起作用。我也更新了描述。 – Shengjie

回答

56

的代码,你发布的作品,我有和的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")); 
    } 
} 

两个测试应该通过与1.9.0的Mockito,powermockito 1.4.12和JUnit 4.8.2

+13

另请注意,如果构造函数是从另一个类中调用的,请将其包含在“PrepareForTest”列表中 –

33

据我所知,你不能用mockito模拟构造函数,只能使用方法。但根据Mockito谷歌代码页上的维基,有一种方法可以通过在您的类中创建一个返回该类的新实例的方法来模拟构造函数的行为。那么你可以嘲笑这种方法。下面是一个excerpt directly from the Mockito wiki

模式1 - 使用一个线方法创建对象

要使用模式1(试验一种名为MyClass的类),你将取代像

Foo foo = new Foo(a, b, c); 
通话

Foo foo = makeFoo(a, b, c); 

和写一行实现方法具d

Foo makeFoo(A a, B b, C c) { 
     return new Foo(a, b, c); 
    } 

重要的是,在方法中不包含任何逻辑;只是创建 对象的一行。其原因是该方法本身永远不会被 单元测试。

当你来测试这个类时,你测试的对象实际上是一个Mockito间谍,用这个方法重写,返回一个 模拟。因此,你正在测试的不是这个类本身,而是它的一个稍微修改过的版本。

您的测试类可能包含成员一样

@Mock private Foo mockFoo; 
    private MyClass toTest = spy(new MyClass()); 

最后,测试方法里面你模拟出调用 makeFoo与像

doReturn(mockFoo) 
     .when(toTest) 
     .makeFoo(any(A.class), any(B.class), any(C.class)); 

线您可以使用更多的匹配具体比任何()如果你想 检查传递给构造函数的参数。

如果你只是想返回你的类的模拟对象,我认为这应该适合你。在任何情况下,你可以在此处详细了解嘲讽对象的创建:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

+10

+1,我不喜欢我需要调整我的源代码使其更适合mockito。感谢分享。 – Shengjie

+15

在编写代码时,让源代码更易于测试,或避免可测试性反模式,这绝对不错。如果您编写的源代码更易于测试,则该代码自动更易于维护。在自己的方法中分离构造函数调用只是实现这一点的一种方法。 –

8

没有使用Powermock ....看到下面的例子基于Ben 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); 
    } 
} 

测试类

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); 
    } 
} 
1

具有的Mockito测试的局限性最终,STA抽动和私人方法。

与jMockit测试库,你可以做一些东西非常容易和直接的,如下:一java.io.File类的

模拟构造函数:

new MockUp<File>(){ 
    @Mock 
    public void $init(String pathname){ 
     System.out.println(pathname); 
     // or do whatever you want 
    } 
}; 
  • 公共构造名称应替换为$ init
  • 抛出的参数和异常保持不变
  • 返回类型应定义为void

模拟一个静态方法:

  • 删除方法模拟签名
  • 方法签名静态保持相同,否则