Mockito - MissingMethodInvocationException

时间:2016-04-26 15:12:47

标签: android mockito retrofit2 rx-android

我正在尝试测试在正确的调度程序上调度API调用并在主线程上观察。

@RunWith(PowerMockRunner.class)
@PrepareForTest({Observable.class, AndroidSchedulers.class})
public class ProductsPresenterTest {

    private  ProductsPresenter presenter;
    @Before
    public void setUp() throws Exception{
        presenter = spy(new ProductsPresenter(mock(SoajsRxRestService.class)));
    }


    @Test
    public void testShouldScheduleApiCall(){
        Observable productsObservable = mock(Observable.class);
        CatalogSearchInput catalogSearchInput = mock(CatalogSearchInput.class);
        when(presenter.soajs.getProducts(catalogSearchInput)).thenReturn(productsObservable);

        /* error here*/ 
        when(productsObservable.subscribeOn(Schedulers.io())).thenReturn(productsObservable);
        when(productsObservable.observeOn(AndroidSchedulers.mainThread())).thenReturn(productsObservable);
        presenter.loadProducts(catalogSearchInput);

        //verify if all methods in the chain are called with correct arguments
        verify(presenter.soajs).getProducts(catalogSearchInput);
        verify(productsObservable).subscribeOn(Schedulers.io());
        verify(productsObservable).observeOn(AndroidSchedulers.mainThread());
        verify(productsObservable).subscribe(Matchers.<Subscriber<Result<Catalog<SoajsProductPreview>>>>any());
    }
}

该行

when(productsObservable.subscribeOn(Schedulers.io())).thenReturn(productsObservable);

抛出以下异常,我不明白为什么因为productObservable是模拟。任何想法或类似的经历?

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

1 个答案:

答案 0 :(得分:2)

问题是由于Observable :: subscribeOn是最终方法,Mockito can't mock。 一种可能的解决方案是使用Powermock:

extension UIFont {
    static func registerFont(bundle: Bundle, fontName: String, fontExtension: String) -> Bool {
        guard let fontURL = bundle.url(forResource: fontName, withExtension: fontExtension) else {
            fatalError("Couldn't find font \(fontName)")
        }

        guard let fontDataProvider = CGDataProvider(url: fontURL as CFURL) else {
            fatalError("Couldn't load data from the font \(fontName)")
        }

        guard let font = CGFont(fontDataProvider) else {
            fatalError("Couldn't create font from data")
        }

        var error: Unmanaged<CFError>?
        let success = CTFontManagerRegisterGraphicsFont(font, &error)
        guard success else {
            print("Error registering font: maybe it was already registered.")
            return false
        }

        return true
    }
}