in my view I have a function which called from presenter with my object, I write a unit test which checks the type of arrived object in that function but how can I check the items in the arrived object(MyModel).
for example, I want to check that the list in my object has 2 items?
in mock View class
final Action1<MyModel> myAction = mock(Action1.class);
#Override
public Func1<Observable<MyModel>, Subscription> invalidAppWidgetIdWidgetModal() {
return RxUi.ui(myAction, Schedulers.immediate());
}
in test method
verify(mViewMock.myAction()).call(any(MyModel.class));
I found the solution, need to use ArgumentCaptor
ArgumentCaptor<MyModel> viewModelCapture = ArgumentCaptor.forClass(MyModel.class);
verify(mViewMock. myAction()).call(viewModelCapture.capture());
assertThat(viewModelCapture.getValue().getListData().size(), is(2));
Related
I'm studying android unit testing and i'm a bit stuck of unit testing for rxjava observable.
This method i'm trying to test:
#Override
public Observable<AuthenticationUsingSqlEntity> logInUsingSql(String token, String ssid) {
SqlRepo sqlRepo = new SqlRepo();
return sqlRepo.authenticate(token, ssid);
}
I have created simple ArgumentCaptor to test that input already the same and have been passed on unit testing what i'm trying to do is to test sql retrofit response but i can't.
I wonder why you provide some method call, but not the actual SqlRepo method to test? The result is, that this only permits for a general answer. And it's unclear, which version you're talking about; I'd assume version 2. However, one can simply chain Observable with .test(), in order to test the Observable itself and there's TestObserver, but there's also TestSubscriber, which can be used to test subscribers and TestScheduler, which can be used to schedule mock RX events. It should be obvious, that the method call which've provided will not suffice to write a proper test, as the method to test is entirely unknown (to me).
In your test on that method, you shouldn't use ArgumentCaptor. Normally, it is used when you need to write a test on a method which receives or creates an object and you want to check the validity of that object as a parameter (for example, that an email address is formatted correctly).
// Create a mock of the OtherClass
OtherClass other = mock(OtherClass.class);
// Run the foo method with the mock
new A().foo(other);
// Capture the argument of the doSomething function
ArgumentCaptor<SomeData> captor = ArgumentCaptor.forClass(SomeData.class);
verify(other, times(1)).doSomething(captor.capture());
// Assert the argument
SomeData actual = captor.getValue();
assertEquals("Some inner data", actual.innerData);
The only test on that method that you can use is a test that checks if the method calls sqlRepo.authenticate. If you want to check the response from Retrofit, then you need to write a test specifically on the method 'authenticate' in the class SqlRepo. Also, if you want to write a test specifically on Observable, then you can use TestObserver. You can then use various methods to check the result you'll receive.
Here's an example:
someService.authenticate()
.test()
.assertNoErrors()
.assertValue( someValue ->
//check if the value is correct
);
Assuming your class is similar to following:
class LoginManager {
#Override
public Observable<AuthenticationUsingSqlEntity> logInUsingSql(String token, String ssid) {
SqlRepo sqlRepo = new SqlRepo();
return sqlRepo.authenticate(token, ssid);
}
}
then with unit testing we are aiming to verify the logic of a unit or function.
in that perspective the logic of your method is that you we offload the login operation to SqlRepo class. And we have to verify this logic.
So as to do that we check whether authenticate function of Sqlrepo is being invoked in response to the invokation of logInUsingSql() method.
we do that by :
loginManagerClassUnderTest = Mockito.spy(loginManagerClassUnderTest);
mockSqlRepo mockSqlRepo = Mockito.mock(mockSqlRepo.class);
doReturn(mockSqlRepo).when(loginManagerClassUnderTest).getSqlRepo();
loginManagerClassUnderTest.logInUsingsql("mockToken", "mockSsid");
ArgumentCaptor<String> tokenCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> ssidCaptor = ArgumentCaptor.forClass(String.class);
verify(mockSqlRepo).authenticate(tokenCaptor.capture(), ssidCaptor.capture());
assertEquals("mockToken", tokenCaptor.getValue());
assertEquals("mockSsid", ssidCaptor.getValue());
As you can see that LoginManager is dependent on SqlRepo class and we have to provide a mock for this dependency so that we ensure that test is carried out in isolation.
so change Loginmanager Function to :
class LoginManager {
#Override
public Observable<AuthenticationUsingSqlEntity> logInUsingSql(String token, String ssid) {
SqlRepo sqlRepo = getSqlRepo();
return sqlRepo.authenticate(token, ssid);
}
public SqlRepo getSqlRepo() {
return new SqlRepo();
}
}
I have a MVVM architecture in my Android app. In an activity, I invoke a method to try to create something from service/repository and return it. I am using RxJava.
Here is the flow:
I click something in view, it invokes method in the Activity.
Method in Activity invokes method in ViewModel.
Method in ViewModel invokes method in Interactor(/use-case).
Interactor has access to service and tries to create something from that service.
Here is the code for this:
Activity:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password);
}
ViewModel:
public class AddWalletViewModel extends BaseViewModel {
private AddWalletInteractor addWalletInteractor;
private final MutableLiveData<Wallet> newWallet = new MutableLiveData<Wallet>();
private final MutableLiveData<ErrorCarrier> newWalletError = new MutableLiveData<ErrorCarrier>();
public LiveData<Wallet> newWallet() {
return newWallet;
}
public AddWalletViewModel(AddWalletInteractor addWalletInteractor) {
this.addWalletInteractor = addWalletInteractor;
}
public Single<Wallet> createWallet(String password){
return addWalletInteractor.addWallet(password)
.subscribe(wallet -> newWallet.postValue(wallet), this::addErrorToLiveData);
}
private void addErrorToLiveData(Throwable throwable){
newWalletError.postValue(new ErrorCarrier());
}
}
Interactor:
public class AddWalletInteractor {
private final KeyStoreServiceInterface keyStoreServiceInterface;
public AddWalletInteractor(KeyStoreServiceInterface keyStoreServiceInterface) {
this.keyStoreServiceInterface = keyStoreServiceInterface;
}
public Single<Wallet> addWallet(String password){
return keyStoreServiceInterface.
createWalletAndReturnWallet(password);
}
}
Service:
#Override
public Single<Wallet[]> getAllWallets() {
return Single.fromCallable(()-> {
Accounts accounts = keyStore.getAccounts();
int amount = (int) accounts.size();
Wallet[] wallets = new Wallet[amount];
for (int i = 0; i<amount; i++){
org.ethereum.geth.Account gethAccount = accounts.get(i);
wallets[i] = new Wallet(gethAccount.getAddress().getHex().toLowerCase());
}
return wallets;
}).subscribeOn(Schedulers.io());
}
Problem is I can not manage to get this to work by tweaking the code. Right now it forces me to cast to (Single) in the return of the createWallet() method in the viewmodel. When running the app, it crashes in that method with:
java.lang.ClassCastException:
io.reactivex.internal.observers.ConsumerSingleObserver cannot be cast
to io.reactivex.Single
at addwallet.AddWalletViewModel.createWallet(AddWalletViewModel.java:31)
Please keep in mind I am new to RxJava, I am still trying to figure it out. Any suggestions here?
The cast performed in the createWallet method will always fail.
Solution 1
The simplest way to fix the crash is to change the return type of that method to io.reactivex.disposables.Disposable, assuming you're using RxJava 2. If you're using RxJava 1, then have it return rx.Subscription. The code you presented that calls the createWallet method doesn't seem to use the returned value so it shouldn't make a difference.
Solution 2
If you really do need the return type to be Single and you want to keep the same behavior, then an alternate solution would be to change the createWallet method as follows:
public Single<Wallet> createWallet(String password) {
return addWalletInteractor.addWallet(password)
.doOnSuccess(wallet -> newWallet.postValue(wallet))
.doOnError(this::addErrorToLiveData);
}
The method now returns a new Single that does whatever the Single returned from addWallet does and additionally invokes the appropriate lambda function when a value is successfully emitted or an error occurs. You would also need to modify the call site for the method as follows:
#Override
public void onCreateWalletClick(String password) {
addWalletViewModel.createWallet(password).subscribe();
}
That subscribe call is needed to have the Single start emitting values. It takes no parameters because you already do all of the interesting work in the createWallet method itself. Both snippets were written with RxJava 2 in mind, but I believe they will also work in RxJava 1 as is.
If you haven't already done so, you should check out the official Rx website as it provides a ton of information on how reactive streams work and how to use them.
Since you're new to RxJava and the documentation is so vast, here's a brief overview of the subscription concept and how it applies to your situation.
RxJava and other stream-based libraries like it have two main components: producers and consumers. Producers supply values and consumers do something with those supplied values.
Single is a kind of producer that only produces one value before terminating. In your case, it produces a reference to the newly created wallet. In order to do something with that reference, it needs to be consumed. That's what the subscribe method on the Single class does. When the Single returned by the addWallet method produces a value, the lambda passed to the subscribe method is invoked and the wallet parameter in that lambda is set to the produced value.
The return type of the subscribe method is NOT itself a Single. When a consumer and a producer are coupled together by the subscribe method, it forms a connection which is represented by the Disposable class. An instance of that class has methods to cancel the connection before the producer is done producing values or to check if the connection has been cancelled. It is this connection object that is returned by the subscribe method.
Note that until this connection is made via one of the subscribe overloads, the producer will not start producing items. I.e., a Single that is never subscribed to will never do anything. It's analogous to a Runnable whose run method is never called.
I am wondering to test my interactor and a piece of test code is mocking the Callback interface that is implemented for different objects on BaseInteractor, that all the Interactors implements.
public interface Callback<T> {
void onSuccess(T response);
void onError(Exception exception);
}
I want to test the onSuccess method and i made this:
#Test
public void shouldGetContributorsSuccess() {
repository = mock(Repository.class);
List<Contributor> contributor = getMockContributor();
GetContributorsInteractor interactor = getFilterReports();
GetContributorsInteractor.Callback callback = mock(GetContributorsInteractor.Callback.class);
interactor.execute(contributor.get(0).getUserName(), "Hello_World", callback);
verify(callback).onSuccess(contributor);
}
when I want to mock the Callback in this line:
GetContributorsInteractor.Callback callback = mock(GetContributorsInteractor.Callback.class);
after that i call verify(callback).onSuccess(contributor);
and show a warning that says Unchecked call to 'onSuccess(T)' as a member of raw type '... .BaseInteractor.Callback'.
I don't know if I should specify in the mock line the specific type as GetContributorsInteractor.Callback but throws an exception or what.
Thanks in advance!
Probably it is because I don't have used mockito before...
UPDATE
I suppress the warnings and I found a error that says:
Argument(s) are different! Wanted:
callback.onSuccess(
[com.example.x.iphonedroid.domain.entities.Contributor#2f686d1f]
);
-> at com.example.x.iphonedroid.domain.GetContributorsInteractorTest.shouldGetContributorsSuccess(GetContributorsInteractorTest.java:61)
Actual invocation has different arguments:
callback.onSuccess(
[]
);
Probably my error becomes from other part that i don't know how to identify but I think I am giving parameters correctly.
In the last line in verify method I pass a "List< Contributor >" and it seems like it would be an empty List.
I looked for the Observer and Observable classes (interface) but I need to create something of more generic.
For example if I would build an observable Paint class I should override many methods.. I don't want this.
I thought maybe is possible to create a custom observer that hold all the methods result of the class to observe and after a isChanged() calling return the status (true or false) comparing the older values with the current values.
The following code method can be used to retrieve all methods inside a generic class:
// Found on http://stackoverflow.com/
public static Method[] getAccessibleMethods(Class clazz) {
List<Method> result = new ArrayList<Method>();
while (clazz != null) {
for (Method method : clazz.getDeclaredMethods()) {
int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
result.add(method);
}
}
clazz = clazz.getSuperclass();
}
return result.toArray(new Method[result.size()]);
}
Once we have the methods listed we can call each method and store the results inside an generic array.
When we need to check for some changes we can refresh all the results and comparing with the olds.
So, the question is: is possible to create this kind of custom observer or there is a valid alternative way (or something already done)?
it's obvious that we can only call the methods with determinated characteristic:
- no parameters methods
- no methods that return void
I just switched over from iPhone to Android and am looking for something similar to where in the iPhone SDK, when a class finishes a certain task, it calls delegate methods in objects set as it's delegates.
I don't need too many details. I went through the docs and didn't find anything (the closest I got was "broadcast intents" which seem more like iOS notifications).
Even if someone can point me to the correct documentation, it would be great.
Thanks!
Never mind... found the answer here :)
http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
Pasting from the article so as to preserve it:
Developers conversant in the event-driven programming model of MS-Windows and the X Window System are accustomed to passing function pointers that are invoked (that is, "called back") when something happens. Java's object-oriented model does not currently support method pointers, and thus seems to preclude using this comfortable mechanism. But all is not lost!
Java's support of interfaces provides a mechanism by which we can get the equivalent of callbacks. The trick is to define a simple interface that declares the method we wish to be invoked.
For example, suppose we want to be notified when an event happens. We can define an interface:
public interface InterestingEvent
{
// This is just a regular method so it can return something or
// take arguments if you like.
public void interestingEvent ();
}
This gives us a grip on any objects of classes that implement the interface. So, we need not concern ourselves with any other extraneous type information. This is much nicer than hacking trampoline C functions that use the data field of widgets to hold an object pointer when using C++ code with Motif.
The class that will signal the event needs to expect objects that implement the InterestingEvent interface and then invoke the interestingEvent() method as appropriate.
public class EventNotifier
{
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier (InterestingEvent event)
{
// Save the event object for later use.
ie = event;
// Nothing to report yet.
somethingHappened = false;
}
//...
public void doWork ()
{
// Check the predicate, which is set elsewhere.
if (somethingHappened)
{
// Signal the even by invoking the interface's method.
ie.interestingEvent ();
}
//...
}
// ...
}
In that example, I used the somethingHappened predicate to track whether or not the event should be triggered. In many instances, the very fact that the method was called is enough to warrant signaling the interestingEvent().
The code that wishes to receive the event notification must implement the InterestingEvent interface and just pass a reference to itself to the event notifier.
public class CallMe implements InterestingEvent
{
private EventNotifier en;
public CallMe ()
{
// Create the event notifier and pass ourself to it.
en = new EventNotifier (this);
}
// Define the actual handler for the event.
public void interestingEvent ()
{
// Wow! Something really interesting must have occurred!
// Do something...
}
//...
}
That's all there is to it. I hope use this simple Java idiom will make your transition to Java a bit less jittery.
The pendant for kotlin.
Define your interface: In my example I scan a credit card with an external library.
interface ScanIOInterface {
fun onScannedCreditCard(creditCard: CreditCard)
}
Create a class where you can register your Activity / Fragment.
class ScanIOScanner {
var scannerInterface: ScanIOInterface? = null
fun startScanningCreditCard() {
val creditCard = Library.whichScanCreditCard() //returns CreditCard model
scannerInterface?.onScannedCreditCard(creditCard)
}
}
Implement the interface in your Activity / Fragment.
class YourClassActivity extends AppCompatActivity, ScanIOInterface {
//called when credit card was scanned
override fun onScannedCreditCard(creditCard: CreditCard) {
//do stuff with the credit card information
}
//call scanIOScanner to register your interface
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val scanIOScanner = ScanIOScanner()
scanIOScanner.scannerInterface = this
}
}
CreditCard is a model and could be define however you like. In my case it includes brand, digits, expiry date ...
After that you can call scanIOScanner.startScanningCreditCard() wherever you like.
The main content of this video tutorial is to show how to use interfaces to delegate methods / data exchange between different Fragments and activities, but it is great example to learn how delegate pattern can be implemented in Java for Android.
Java callback is not the same thing like ios delegate, in ios you can use a callback almost the same way like in Android. In Android there is startActivityForResult that can help you to implement the tasks for what ios delegate is used.
I believe ListAdapter is a example of delegation pattern in Android.
Kotlin's official Delegation pattern:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
See: https://kotlinlang.org/docs/delegation.html