I have a function that returns a Completable which returns Completable.error(RuntimeException("message")) if another function fails or Completable.complete() if not.
I was trying to write a unit test for this and see that the flow is going correctly to the error and success code but in my test I cannot differentiate between them using
underTest.unregisterFromService().test().assertComplete().assertNoErrors()
Does anyone know how the Completable.error() value can be checked in unit test?
I believe what you're looking for is
yourCompletable
.test()
.assertErrorMessage("your error message")
There is an assertError for that, most cases use the version that takes the Thorwable's type as a parameter, from the docs:
Asserts that this TestObserver/TestSubscriber received exactly one onError event which is an instance of the specified errorClass class.
Usage:
yourCompletable
.test()
.assertError(RuntimeException::class.java)
Here you can find the three versions of assertError.
Related
I need to run a unit test based on whether this asset exists at runtime. The reason is, I am downloading the file in react native and in android, I am running some unit tests that requires this file.
I would like to run the unit test only if this file exists. Does anyone have any suggestions or code samples on how this can be achieved? Or is there another way these unit tests can be accomplished?
You shouldn't do that in a unit test because you want to have the file locally in your testing environment or have a mock that provides it. Otherwise you're not Eradicating Non-Determinism in Tests.
Let's assume you need to do something like that anyway. So, I would add a condition in the assert expression:
#Test
fun `Given a variable When has a value Then assert it has a value`(){
var myVar = null
myVar = getAValue()
myVar?.let {
assertNotEquals(null, myVar)
}
}
To me, eradicating non determinism in this particular context means that test scope has always specific expected values, the conditional expression in the let or an if enclosing an assert expression violates that. Hence the code above shouldn't be part of your tests. Instead, you have to write a test for the case myVar is null, you write another test for the case myVar is non null.
That's why I use Given, When, Then the conditional state would make the Given/When very messy.
I have a ViewModel in which there is a method which has the following line of code:
billDate.set(!TextUtils.isEmpty(SampleApp.getInstance().getAccountManager().getDueDate()) ?
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
SampleApp.getInstance().getAccountManager().getBillingDueDate()) :
SampleApp.getInstance().getApplicationContext().getString(R.string.missing_due_date));
I have a test class using Mockito to test the different methods in ViewModel. But it is failing with NullPointerException at this line:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
Below is the log:
java.lang.NullPointerException
at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
at java.util.regex.Matcher.reset(Matcher.java:309)
at java.util.regex.Matcher.<init>(Matcher.java:229)
at java.util.regex.Pattern.matcher(Pattern.java:1093)
at java.util.Formatter.parse(Formatter.java:2547)
at java.util.Formatter.format(Formatter.java:2501)
at java.util.Formatter.format(Formatter.java:2455)
at java.lang.String.format(String.java:2940)
While running a test case, I see the log showing some error related to Pattern
Can somebody suggest, how to test the String.format() method?
First of all, you should not be importing android view packages into your ViewModel. So skip using things like TextUtils inside ViewModels.
As to the getApplicationContext().getString(), create an interface for this. Something like:
interface StringProvider {
String getString(int resource);
}
Then pass that interface in your ViewModel constructor and use that to get the string you want.
When you initialize the ViewModel, you can pass a concrete implementation of StringProvider like this:
class StringProviderImpl implements StringProvider {
String getString(int resource) {
return SampleApp.getInstance().getApplicationContext().getString(resource);
}
}
This way, for your unit tests, you can just mock StringProvider and don't have to worry about dealing with contexts inside your ViewModel and the related test code.
You don't need to test the String.format method. That is not your code, and your goal should be to test your own code. But your code is using that method, so you need to test your code. This is the part you are trying to validate or mock out as I understand it:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due), SampleApp.getInstance().getAccountManager().getBillingDueDate())
which makes several calls to SampleApp to get an instance. Since those calls to SampleApp.getInstance are static method calls, you won't be able to mock them out. There isn't enough code posted to know what SampleApp is or what SampleApp.getInstance() returns or to know if any of the subsequent calls on that instance are returning null, but one of them is. So I think to solve this you need to look at the what the getInstance method returns. If you can't touch that code and you're hoping to only modify your test classes, you may not be able to test this with mockito due to the static method.
But otherwise you will need to build a way for your tests so the call to SampleApp.getInstance returns a mock object as the instance instead of whatever real instance I presume it is returning now. Then you can mock out the subsequent methods like getApplicationContext and getString to make them return canned responses so that the string.format call will not fail on a null input.
One note of caution--if you do end up making the static getInstance method return a mock, but sure you have proper cleanup when your test is done to set it back to what it was returning originally so you don't inadvertently modify something that might cause another unrelated unit test to fail. That is always a risk if you change something returned by a static method in a unit test since you are effectively changing it for all tests.
Considering that the test fails after the AccountManager was already used, you should have set up the SampleApp as a mock or fake already.
SampleApp app = SampleApp.getInstance()
AccountManager am = app.getAccountManager();
Context context = app.getApplicationContext();
billDate.set(!TextUtils.isEmpty(am.getDueDate()) ?
String.format(context.getString(R.string.due), am.getBillingDueDate()) :
context.getString(R.string.missing_due_date);
Now you only need to make sure to mock the Context you provide with with app.getApplicationContext() or the SampleApp itself, if you use app.getString() directly.
doReturn(dueFormatString).when(context).getString(R.string.due);
doReturn(dueMissingString).when(context).getString(R.string.missing_due_date);
But in general you should abstract the Context away. Not using it will simplify your code and therefore your testing a lot.
Also consider using context.getString() instead of String.format() for formatting a string you load from a resource. It's as easy as adding the format arguments as parameters to the call.
context.getString(R.string.due, am.getBillingDueDate())
I am trying to write Roboelectric test for activity.finishAffinity() method instead of activity.finish(). I tried asserting activity.isFinishing() to true but I am getting AssertionError.
what will be probable solution for this?
I have a piece of Observable which in the end either returns an error and retries or just returns onNext. I don't need anything in onNext, so this is just an Observable<Unit>.
Now the problem is that at the end of the chain I have to hit this onNext and I don't have anything other than good old Observable.just(). But I cannot return Observable.just(null) because it returns Nothing?, not Unit. I cannot return Unit, because it's not instantiable. Therefore I have Observable.just(null).map{}. It works, but looks ugly. Any idea for a better solution?
Use Observable.just(Unit). Unit itself is the single object of the type Unit.
This unit test is not hitting the Firebase server. If the same unit test is run using a breakpoint, it will hit the server. This leads me to believe it may be related to the thread that Firebase is using for background work.
I tried running the code on the UI thread, but there was no change. I have also tried using the instrumentation context when getting the Firebase instance.
Why does this code only work when using a breakpoint?
#RunWith(AndroidJUnit4::class)
class FirebaseTest : AndroidJUnitRunner() {
#Test
#Throws(Exception::class)
fun doTheTest() {
FirebaseDatabase.getInstance().reference.child("test").push()
assertTrue(true)
}
}
push() itself doesn't do anything on the server, so I don't think you would ever see a change if all you executed was that one line of code. push() just generates a key value (based on the current time) and constructs a DatabaseReference that points to that key. Nothing is written until you write something to the DatabaseReference, like this:
val ref = FirebaseDatabase.getInstance().reference.child("test").push()
ref.setValue(...)
That will asynchronously write the value you give to that location at the key generated by push(), and you can't expect that it will have completed the transaction by the end of the test, unless you block the test until it verifies that completed the round trip.