用mockito模拟方法里面创建对象

下文为转载,但原文有问题,错误的地方特地标红了

Introduction

Code in which new objects are created can be difficult to test. There are a number of patterns for doing this; two of them are discussed here. Both of these patterns may require rearranging your code a little, to make it more testable. Writing code that's easily testable is a good thing to be doing, regardless of which mocking framework you end up using.

Details

Pattern 1 involves factoring uses of new into one-line methods, then using a Mockito spy. This is the simpler of the two patterns. Pattern 2 involves factoring uses of new into a separate class and injecting it. It's a little more work, but it can be more powerful. The new calls that you want to factor out (using either pattern) are those where an object is created, that you are likely to want to mock. It is recommended that you use one or other of these patterns, whenever you find yourself writing new, on a class that's in your code base (as opposed to a JDK class or a class from a third party library).

Pattern 1 - using one-line methods for object creation

To use pattern 1 (testing a class called MyClass), you would replace a call like

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

with

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

and write a one-line method

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

It's important that you don't include any logic in the method; just the one line that creates the object. The reason for this is that the method itself is never going to be unit tested.

When you come to test the class, the object that you test will actually be a Mockito spy, with this method overridden, to return a mock. What you're testing is therefore not the class itself, but a very slightly modified version of it.

Your test class might contain members like

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

Lastly, inside your test method you mock out the call to makeFoo with a line like

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

You can use matchers that are more specific than any() if you want to check the arguments that are passed to the constructor.

Pattern 2 - the factory helper pattern

One case where this pattern won't work is if MyClass is final. Most of the Mockito framework doesn't play particularly well with final classes; and this includes the use of spy(). Another case is where MyClass uses getClass() somewhere, and requires the resulting value to be MyClass. This won't work, because the class of a spy is actually a Mockito-generated subclass of the original class.

In either of these cases, you'll need the slightly more robust factory helper pattern, as follows.

public class MyClass{ 
    static class FactoryHelper{ 
        Foo makeFoo( A a, B b, C c ){ 
            return new Foo( a, b, c ); 
        } 
    } 

    //... 

    private FactoryHelper helper; 
    public MyClass( X x, Y y ){ 
        this( x, y, new FactoryHelper()); 
    } 

    MyClass( X x, Y, y, FactoryHelper helper ){ 

        //... 

        this.helper = helper; 
    } 

    //... 

    Foo foo = helper.makeFoo( a, b, c ); 
} 

So, you have a special constructor, just for testing, that has an additional argument. This is used from your test class, when creating the object that you're going to test. In your test class, you mock the FactoryHelper class, as well as the object that you want to create.

@Mock private MyClass.FactoryHelper mockFactoryHelper; 
@Mock private Foo mockFoo; 
private MyClass toTest; 

and you can use it like this

toTest = new MyClass( x, y, mockFactoryHelper ); 
when( mockFactoryHelper.makeFoo( 
    any( A.class ), any( B.class ), any( C.class )))
    .thenReturn( mockFoo ); 

As with pattern 1, you can use matchers that are more specific than any() if you need to.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值