2016-05-16 71 views
2

我正在使用Junit4Mockito编写我的测试用例。在其中一个正在测试的类中,有一个函数init(),它从构造函数中调用。无法存根android.os.Handler的post方法

void init(){ 
//Some code 
    Handler handler = new Handler(Looper.getMainLooper()); 
    handler.post(new Runnable() { 
     @Override 
     public void run() { 
     //Some code 
     } 
    }); 
} 

尝试创建该类的constructor时引发以下异常。

java.lang.RuntimeException: Method post in android.os.Handler not mocked. 

然后我尝试使用下面的代码

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 

但我仍不断收到同样的exception嘲笑Handler类的post方法。我应该如何对Handler类的post方法进行存根?

回答

0

很难说没有看到更多的背景,但我看到两种选择。

首先,如果你有能力,你可以避免使用new来模拟你需要的东西。你可以在构造函数中注入它,或者在构造函数中注入一个工厂并模拟工厂,这样你就可以从中模拟Handler了。对于大多数情况,沿着这些方向的东西是首选方法。

如果这样做不实际,可以使用PowerMock to construct new objects

使用PowerMockito.whenNew,例如,

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
whenNew(Handler.class).withExpectedArguments(looper).thenReturn(handler); 

该代码未经测试,但应基本上工作。

0

你是正确的解释“法不嘲笑”:您正在使用a no-implementation version of the Android system library,所以你需要在这里使用嘲讽,或者你需要切换到一个图书馆一样Robolectric具有的类的Java实现比如Handler测试。

您将需要doReturn为您的存根(stub)。一个when语法有趣的意外的方面是,它实际上调用该方法它的磕碰:

when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
// calls 
// handler.post(   null   ) 

而且,由于间谍默认调用真正的方法,你会实际调用问题的方法,而试图存根它。相反,请使用doReturn告诉Mockito暂时停用存根。

doReturn(true).when(handler).post(Matchers.any(Runnable.class)); 

你需要存根注入到你的测试。这是一个有点棘手,因为你在构造函数中做“繁重”你失去了一个后期建设机会,换掉你的经理。 jhericks mentions a PowerMock solution,虽然我建议重构,所以你不要做建筑这么多,作为第三个选择,你可以解决这个与测试过载:

public class YourClass { 
    /** Public constructor for external access. */ 
    public YourClass() { 
    this(new Handler(Looper.getMainLooper())); 
    } 

    /** Package-private constructor for testing. */ 
    YourClass(Handler handler) { 
    init(handler); 
    } 

    private void init(Handler handler) { 
    handler.post(new Runnable() { 
     @Override public void run() { 
     //Some code 
     } 
    }); 
    } 
} 

旁注:要格外小心,init是私人或最后,因为it's dangerous to call overridable methods from constructors