I'm having problem with mockito. I'm mocking a class and then using thenReturn() on on of its method. but seems like something is going wrong. here is the code.
TestCode:
public void getCardsTest() {
FeatureFragmentPresenterImpl presenter = new FeatureFragmentPresenterImpl();
GroupFeatureData data = Mockito.mock(GroupFeatureData.class);
FeatureFragmentView view = Mockito.mock(FeatureFragmentView.class);
presenter.init(view, data);
Observable<Response<ResponseBody>> errorObservable = Observable.error(new IOException());
assertNotNull(observable);
Mockito.when(data.getCards(Mockito.anyString(), Mockito.anyString(),
Mockito.anyInt(), Mockito.anyInt())).
thenReturn(errorObservable);
presenter.getAllCards(new Contact(new Name("ssd")), -1);
}
Presenter code :
public void getAllCards(IContact iContact, int lastIndex) {
Observable<Response<ResponseBody>> allCardsResponseObservable = mGroupFeatureData.getCards(path, id, 10, lastIndex);
allCardsResponseObservable
.subscribeOn(Schedulers.io()) -------> Test Failing because NPE here
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<Response<ResponseBody>>() {
#Override
public void onNext(#NonNull Response<ResponseBody> response) {
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
});
}
public void init(FeatureFragmentView featureFragmentView,
GroupFeatureData groupFeatureData) {
this.mGroupFeatureData = groupFeatureData;
this.mFeatureFragmentView = featureFragmentView;
}
Even though i'm mocking response of data.getCards() in Test, In presenter it is throwing NPE whereas it should just operate on mocked Observable that is errorObservable. what is going wrong here?
The NPE tells us that this line:
mGroupFeatureData.getCards(path, id, 10, lastIndex);
... returns null which implies that the actual method call and the method call which you mocked here ...
Mockito.when(data.getCards(Mockito.anyString(), Mockito.anyString(),
Mockito.anyInt(), Mockito.anyInt())).
thenReturn(errorObservable);
... do not match. The code supplied shows this actual call:
Observable<Response<ResponseBody>> allCardsResponseObservable =
mGroupFeatureData.getCards(path, id, 10, lastIndex);
Breaking this call down we can say that:
The third argument 10 is an int so this will match the given argument matcher: Mockito.anyInt()
The fourth argument lastIndex is declared as an int so this will match the given argument matcher: Mockito.anyInt()
The type of the first and second argments is not clear from your code extract since we do not see where path and id are declared but unless they are both of type String then the given argument matchers for these parameters (Mockito.anyString()) will not match and hence the mocked call will return null.
So, it looks to me like one or other of path and id are not actually of type String. It would be useful if you could update your question to show where these types are declared.
Related
I am writing a native plugin that, in some cases, has to call functions in the Flutter portion of the app, written in Dart.
How it's achieved, is explained here:
https://flutter.io/platform-channels/
Furthermore, an example of invoking a method from the native/platform part towards the Dart/non-native is here:
https://github.com/flutter/plugins/tree/master/packages/quick_actions
Now, this example is really nice in case the platform only needs to invoke a method, i.e. that call returns nothing/void, but in case it needs to invoke a function, i.e. needs a return value from the non-native/Dart part, I could not have found an example or documentation on the internet. I believe it can be implemented though, because in the native Java part, there is a method:
public void invokeMethod(String method, Object arguments, MethodChannel.Result callback)
So, there is a callback object that could have a return value from the non-native part - or, I am mistaken here, and there is currently no way of returning a value from the non-native Dart portion of the app?
The signature is void setMethodCallHandler(Future<dynamic> handler(MethodCall call)), so we need to provide a function at the Dart end that returns Future<dynamic>, for example _channel.setMethodCallHandler(myUtilsHandler);
Then implement the handler. This one handles two methods foo and bar returning respectively String and double.
Future<dynamic> myUtilsHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case 'foo':
return 'some string';
case 'bar':
return 123.0;
default:
throw MissingPluginException('notImplemented');
}
}
At the Java end the return value is passed to the success method of the Result callback.
channel.invokeMethod("foo", arguments, new Result() {
#Override
public void success(Object o) {
// this will be called with o = "some string"
}
#Override
public void error(String s, String s1, Object o) {}
#Override
public void notImplemented() {}
});
In Swift, the return value is an Any? passed to the result closure. (Not implemented is signaled by the any parameter being the const NSObject value FlutterMethodNotImplemented.)
channel.invokeMethod("foo", arguments: args, result: {(r:Any?) -> () in
// this will be called with r = "some string" (or FlutterMethodNotImplemented)
})
I am invoking an AWS Lambda function directly from my Android app. I have the Request class:
private class MyRequest
{
String param;
public SetIdentityRequest() {}
public SetIdentityRequest(String param) {this.param = param;}
public String getParam() { return param; }
public void setParam(String param) { this.param = param; }
}
I don't need any values returned, so I don't have a Response class. I tried making an empty one in case that was causing my problem, but I got a lot more errors.
My interface class:
private interface MyLambda
{
#LambdaFunction
void myLambda(MyRequest req);
}
And finally my code for calling it:
LambdaInvokerFactory factory = new LambdaInvokerFactory(getApplicationContext(), Regions.US_EAST_1, credentialsProvider);
MyLambda lambda = factory.build(MyLambda.class);
lambda.myLambda(new MyRequest(someString));
Now, the lambda does actually go through and execute properly, so this isn't a dealbreaking kind of error; but I've been seeing when I step through it in debug that the line that has factory.build gets an error Method threw 'java.lang.UnsupportedOperationException' exception. Cannot evaluate com.myapp.$Proxy1.toString(). What is this error about? Do I need to worry about it? What do I need to do to stop getting this error?
SOLVED: Even if the getValue() on the Argument Captor shows you this, it is normal. To be honest I was expecting to see and instance on the OnLoginWithEmailCallback interface here. The problem on my side was related to a method call on mView which was generating a NPE. Works like a charm now.
ORIGINAL PROBLEM:
I am implementing my first unit test using Mockito in my MVP app and I need to mock the behaviour of a callback when the user is logging in. I am using Firebase to handle the authentication.
I followed a very good tutorial from here : https://fernandocejas.com/2014/04/08/unit-testing-asynchronous-methods-with-mockito/.
I am calling method on class under test. This method calls another one on the Auth Presenter which does the actual work
mPresenter.performLoginWithEmail(EMAIL, PASSWORD);
Then I am verifying that an underlining method in the Auth Presenter class was called. I try to capture the callback interface.
verify(mAuthPresenter, times(1)).login(mOnLoginWithEmailCallbackArgumentCaptor.capture(),
eq(EMAIL), eq(PASSWORD));
The problem is that getValue() from the Argument Captor returns an instance of the mPresenter (class under test) instead of the OnLoginWithEmailCallback interface class. Therefore I get an NPE.
mOnLoginWithEmailCallbackArgumentCaptor.getValue().onLoginWithEmailSuccess();
Here is the complete test class:
#RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {
private static String EMAIL = "test#rmail.com";
private static String PASSWORD = "1234";
//class under test
private LoginPresenter mPresenter;
#Mock
AuthPresenter mAuthPresenter;
#Captor
private ArgumentCaptor<OnLoginWithEmailCallback> mOnLoginWithEmailCallbackArgumentCaptor;
#Mock
ILoginActivityView mView;
#Before
public void setupLoginPresenter() {
MockitoAnnotations.initMocks(this);
// Get a reference to the class under test
mPresenter = new LoginPresenter(mView, mAuthPresenter);
}
#Test
public void performLoginWithEmail() {
mPresenter.performLoginWithEmail(EMAIL, PASSWORD);
//wanting to have control over the callback object. therefore call capture to then call methods on the interface
verify(mAuthPresenter, times(1)).login(mOnLoginWithEmailCallbackArgumentCaptor.capture(),
eq(EMAIL), eq(PASSWORD));
mOnLoginWithEmailCallbackArgumentCaptor.getValue().onLoginWithEmailSuccess();
InOrder inOrder = Mockito.inOrder(mView);
inOrder.verify(mView).goToMap();
inOrder.verify(mView).hideProgressBar();
}
}
EDIT: This is the call to mAuthPresenter.login:
SOLVED: getLoginActivityView() was causing an NPE
public void performLoginWithEmail(String email, String password) {
mAuthPresenter.login(new OnLoginWithEmailCallback() {
#Override
public void onLoginWithEmailSuccess() {
getLoginActivityView().goToMap();
getLoginActivityView().hideProgressBar();
}
#Override
public void onLoginWithEmailFailed(String error) {
getLoginActivityView().hideProgressBar();
getLoginActivityView().showToast(error);
}
}, email, password);
}
I also tried using using doAnswer from Mockito:
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((OnLoginWithEmailCallback)invocation.getArguments()[0]).onLoginWithEmailSuccess();
return null;
}
}).when(mAuthPresenter).login(
any(OnLoginWithEmailCallback.class, EMAIL, PASSWORD));
Still, invocation.getArguments() return an instance of the class under test (LoginPresenter), so the same problem as before. Can you help me?
The problem was that i got confused by the Argument Captor which returned me an instance of the caller class (LoginPresenter). The problem in my case was with a method inside the anonymouse class OnLoginWithEmailCallback() which was throwing an NPE.
In my current Android application I am investigating the use of #AspectJ
I am attempting to "capture" all executions to methods whose signature resembles:-
public void onMethodClicked(com.example.CustomType customType) {}
I have the following POINTCUTS
1) Ignore my Aspect class:
#Pointcut("!within(com.example.aspect)")
public void notAspect() { }
2) Select all "Clicked" methods with customType argument
#Pointcut("execution(* com.example..*.*Clicked(com.example.CustomType)) && args(custom)";)
public void customClicked(CustomType custom) { }
3) My #Around:-
#Around("notAspect() && customClicked()")
public Object selectedClicked(final ProceedingJoinPoint joinPoint, CustomType custom) throws Throwable {
Log.d(TAG, "Found a clicked method " + custom);
Object result = joinPoint.proceed();
return result;
}
When I build my Android Application I get these messages
no match for this type name: CustomType [Xlint:invalidAbsoluteTypeName]
bad parameter to pointcut reference
formal unbound in pointcut
no match for this type name: com.example.aspect [Xlint:invalidAbsoluteTypeName]
the parameter custom is not bound in [all branches of] pointcut
use of ProceedingJoinPoint is allowed only on around advice (arg 1 in (before(extraFlags: 2): (((!within(com.example.aspect+) && execution(* com.example..*.*Clicked(com.example.CustomType)) && args(custom)) && persingleton(com.example.aspect.TraceAspect))->void com.example.aspect.TraceAspect.selectedClicked(org.aspectj.lang.JoinPoint, com.example.CustomType)))
What have I done wrong?
UPDATE
I have fixed one of the error/warning messages by correcting the !within() as follows:-
1) Ignore my Aspect class:
#Pointcut("!within(com.example.aspect.TraceAspect)")
public void notAspect() { }
I'm not sure about your problem but you may try changing the POINTCUT like this.
#Pointcut("!within(com.example.aspect.TraceAspect)")
public void notAspect() { }
#Pointcut("execution(* com.example..*.*Clicked(com.example.CustomType)))
public void customClicked() { }
Look I've removed the args(custom) part here which go inside the #Around annotation. And yes, of course I've removed the function parameter argument of customClicked function and the semi-colon by the end of the statement.
Now write your selectedClicked function like this by passing the arguments from here.
#Around("notAspect() && customClicked() && args(custom)")
public Object selectedClicked(final ProceedingJoinPoint joinPoint, CustomType custom) throws Throwable {
Log.d(TAG, "Found a clicked method " + custom);
Object result = joinPoint.proceed();
return result;
}
It should work with no failure.
I am having problems with EventBus 3.0.0 where I post a single event like this:
Call<List<SessionSpec>> call = httpService.getSessionSpecs();
call.enqueue(new Callback<List<SessionSpec>>() {
#Override
public void onResponse(Call<List<SessionSpec>> call, Response<List<SessionSpec>> response) {
if (response.isSuccessful()) {
List<SessionSpec> specs = response.body();
EventBus.getDefault().post((List<SessionSpec>)specs);
}
else Log.e(TAG, "sendSessionSpecs(): request NOT successful");
}
#Override
public void onFailure(Call<List<SessionSpec>> call, Throwable t) {
Log.e(TAG, "sendSessionsSpecs(): failed");
}
});
I have two subscribers in the same fragment, each with different signatures, but they are both getting called from a single post:
#Subscribe
public void onSessionSpec(List<SessionSpec> specs) {
Log.d(TAG, "onSessionSpec(): entered");
Log.d(TAG, " : number of session specs: " + specs.size());
}
The second subscriber is defined as:
#Subscribe
public void onOverlayType(List<OverlayType> types) {
Log.d(TAG, "onOverlayType(): entered");
Log.d(TAG, " : number of overlay types: " + types.size());
}
Both of these callbacks are in a single fragment which is active when the post is done and I have verified that the post is only called once. When the single SessionSpec event is posted, both the onSessionSpec and the onOverlayType callbacks are dispatched by EventBus with the event type of List> so the onOverlayType callback receives the wrong type in its callback argument. The class OverlayType is a simple POJO class with 2 members, a int "sid" and a String "name". The class SessionSpec is more complex; it does have a member String "name" but other than that, nothing else is common between these 2 classes. I have verified that there is nothing closely resembling "OverlayType" in the SessionSpec class.
The interface definition is this:
public interface VcapHttpInterface {
#GET("overlay/types")
Call<List<OverlayType>> getOverlayTypes();
#GET("session/list")
Call<List<SessionSpec>> getSessionSpecs();
#GET("session/{id}")
Call<Session> getSession(#Path("id") int sid);
}
The getSession event post/callback has no problems.
I have spend all day trying to figure what is going wrong so I am clueless at this point. Anybody know what might be wrong with my code?
Thanks,
-Andres
Edit: How does EventBus know which handler to call for a particular response? Some posts I have read said that EventBus does not use the handler signature, but how else would it know how to map a response to the right subscribed handler routine? Is there a way to explicitly define the handler callback for a given event?
EventBus checks the class of the object that you are posting, and calls the methods that expect that class in their parameters. In your case you are posting an object which is a List. In both your listeners you expect an object of type List. It doesn't matter what generic you put in OverlayType or SessionSpec, eventbus will call both. In order to make it work you gotta define to models as events.
public class OverlayTypeEvent {
public List<OverlayType> types;
public OverlayTypeEvent(List<OverlayType> types) {
this.types = types;
}
}
and
public class SessionSpecEvent {
public List<SessionSpec> types;
public SessionSpecEvent(List<SessionSpec> types) {
this.types = types;
}
}
And listen on them seperatley. Then post events with the specific type.
#Subscribe
public void onSessionSpec(OverlayTypeEvent event) {
List<OverlayType> overlayTypes = event.overlayType;
}
If you don't want to create new class as a container everytime you send a list data, you can you Pair as simple container, it has two generic fields (first and second) to contain variables.
You can use first as a key to check the type of class, second contains the actually data.
List<SessionSpec> specs = response.body();
EventBus.getDefault().post(new Pair<>(SessionSpec.class.getSimpleName(), specs));
Receive data:
#Subscribe
public void onSessionSpec(Pair<String, List<SessionSpec>> specContainer){
if (SessionSpec.class.getSimpleName().equals(specContainer.first)) {
List<SessionSpec> sessionSpecs = specContainer.second;
}
}
#Subscribe
public void onOverlayType(Pair<String, List<OverlayType>> overlayContainer) {
if (OverlayType.class.getSimpleName().equals(overlayContainer.first)) {
List<OverlayType> overlayTypes = overlayContainer.second;
}
}
Advantage of this solution: Reduce creating unneeded classes.
Disadvantage: both onSessionSpec and onOverlayType get called.