Is there a way to simulate or mock FingerprintManager.authenticate()? I want to write instrumented tests for my fingerprint authenticator.
I'm fine if there's a solution with a restriction that the tests can be run either on an emulator or a device. I use JUnit 4.12.
I might suggest that you don't mock it, in the spirit of not mocking things you don't own. What I might suggest instead (from the above link):
The prescription implied by "don't mock what you don't own" is to introduce your own shim/wrapper/adapter around it. This effectively cordons off the dependency to a single place in your codebase and contextualizes it in the consistent and easy-to-use style you're trying to promote within your codebase. If there's anything awkward about how one needs to invoke the dependency (maybe a chaining API, multi-step invocation, repetitive default configuration, etc.), it can be swept under the rug into that common adapter.
This feels like an instance where the humble object pattern might be appropriate.
Related
I'll be developing an Android app in Kotlin and I'm trying to figure out how to initialize emulated dependencies. For example, the app will make API calls to a server, obtain the user's location from a location provider, pull down images from a content management system, store data locally in a database and in Android's Shared Preferences, and do math based on the current date/time. Thus there are a lot of external dependencies I want to emulate, including the current date/time so I can verify age calculation, etc.
My goal for testing is just to validate my app's screens using an Android instrumented test. I don't want any dependency on real external systems because testing those systems is the responsibility of the developers of those systems.
While reading Android'd documentation Consider whether to use test doubles, I noticed it offered a good tip: "Tip: Check with the library authors to see if they provide any officially-supported testing infrastructures, such as fakes, that you can reliably depend on." However, the documentation doesn't really explain how to initialize a 3rd party test infrastructure.
Below are what I understand so far about my options, but they all come back to a fundamental thing I don't understand: how does an Android app under test know it should operate in a test mode vs. a production mode?
Mocking such as Mockito or MockK: Mocking seems like a special case of Dependency Injection tailored for testing. The examples I've seen involve testing a class or a method, not a full scale system. The examples typically show how you mock a class and pass it to the class/method under test. But with a full scale system, the test code operates on widgets referenced via Espresso. There is no access to the classes where the logic is. My impression is mocking is for unit testing, not UI testing. But maybe someone can explain how to use mocking for UI testing:
a) Suppose an external dependency is initialized deep in the call stack. If I define a mock in my test code's setup function (e.g. a method annotated with #Before), how do I pass that down to the place in the code that depends on it?
b) I keep reading that mocks don't work in Kotlin because Kotlin defines all classes as final. There seem to be a few work arounds. But does does Google/Android officially recommend one of these (I haven't read it in their documentation).
Dependency Injection such as Dagger 2: If mocking isn't viable for UI testing, then should I use Dependency Injection? From what I understand, it seems Dagger 2 deals with issue 1.a above by defining a top-level Component and a tree of Modules which can provide dependencies at any layer of the stack. For testing, it seems like I would just provide a different Component that emulates the real dependencies.
a) In an Android instrumented test, where do instantiate a Dagger 2 Component designed for testing. How do I make sure that Component is used rather than the Component intended for production?
Prepare before launching test: I can see how I could customize build.gradle to prepare my test environment before my application is launched. For example, I could pass a flag to my app so that when the Application's onCreate() gets called, I can configure my system to prepare emulated dependencies via Dependency Injection, Mocking, or even just a custom implementation. For example, some external dependencies have a test mode where I would need to pass a flag to them so they work in test mode. I'm not clear how that sort of thing reconciles with Dependency Injection or Mock but I guess I could see how I could use those mechanisms as a wrapper to pass the test flag or not. In the following post someone wanted to mock a location provider and to do that they modified their build.gradle file to set things up before the Android test infrastructure started.
How to set Allow Mock Location on Android Device before executing AndroidTest with uiautomator and espresso?
In conclusion, I want to test a Kotlin Android app's UI using Android instrumented test with Espresso but I don't know how to setup the test so that external dependencies use emulation code rather than production code. Should I use mocking, Dependency Injection, or customize via build.gradle? Can someone help me get my thinking on track?
After much searching, I've discovered that the Android ActivityTestRule allows you to defer launching the Activity. This gives the test code time to initialize emulated dependencies as demonstrated in Fast Mocked UI Tests on Android Kotlin.
I have been going through source code of Volley and have found that for every class or interface there is a test implementation.
Is it preferable to write Test class for every other class than using Mockito to just mock objects?
A broad question but let's collect the underlying facts:
writing your own custom test "stubs" enables you to implement your "own" vision of "test support"
especially, you do not have any dependencies to a mocking framework
In other words: you decide to re-invent the wheel to a certain degree. That prevents you running into bugs other people put down, at the risk of making your own mistakes.
In that sense, this boils down to the old discussion "buy or make yourself".
When talking about test cases, there are various experts that suggest to not rely on mocking frameworks. So this is a common practice, but I think a "minority" one.
My personal two cents here: ideally, you should write production code that can be tested without any mocking framework. But that isn't always possible. And for those cases, you have one mocking framework in your toolbox. You know how to use that in a reasonable way to get your testing done. I would find it way too cumbersome to do all test stubs manually. A lot of effort for a relatively small gain.
I am wondering if there is an option to test client library which uses Android (mock) and calls backend running on some endpoint?
The use case could be:
Have a library called 'A' that requires android's context (extracts data from it) and Google Services (could be mock). Then call A.sendData(context) that collects data such as advertising id, phone info, ...
So the test lifecycle could be:
A.sendData(context) → waits for server response → assert result.
I've read everywhere that Robolectric can't be used as an integration framework. I've created an Instrumented test with some UI which did the trick BUT running it takes ages and doesn't work properly on remote CI (timeouts, sometimes it passes sometimes it doesn't).
I need to mock 'just' part of Android device (no need for UI) and test if backend returns valid data so probably no need for emulator. OR if the emulator is needed I would like to create a test that uses emulator but there is no need to write UI test.
Is out there anything like this?
It seems to me all you're trying to do is validate a network component sends the appropriate data to a server and handles the appropriate response. For this kind of test, I think Robolectric would suit the needs just fine. It should be able to fill the Context of your app which can then be injected in to your component. All while being run through the JUnit framework which is significantly faster than instrumentation tests.
Though, if all you're trying to do is make sure your network component works. Then you may not actually need the Android framework. You could instead rewrite your class using pure Java. Just strip out the items you need from Context, and inject those in to your classes. Then you can use the JUnit testing framework which runs on the computer instead of the device. It's much faster and doesn't require a phone. This works as long as they're not Android specific components such as Drawable. This will also not work if you require Google Services.
A very tedious method is to use Mockito and PowerMock to mock the methods of your Context and Play Services. You just mock the methods that your Context class is going to use. This can get really complicated though. You can use this alongside Robolectric so you only have to mock what you need to mock.
As far as integrations tests are concerned, there's absolutely no need to write a UI test when writing integration tests. Basically what the integration tests do is create a test Application that runs on the phone. If you don't provide an UI, then you won't use an UI. It'll just show a blank screen while the test runs. You can use InstrumentationRegistery#getContext() to retrieve the context that's used in your application. Then inject the context in to your components that need it.
Though, this can sometimes even be a pain and instrumentation tests take longer even without any UI. But, if you want to make sure it works with an actual Android Context with actual Google Services, this is the best way.
So the basic strategy is to write a whole bunch of small, fast unit tests using Robolectric on JUnit framework which can be run a bunch of times. Then write your comprehensive validation tests using instrumentation framework to make sure everything works together nicely.
My apps are mostly GUIs that communicate to a server for most of their information. If anything goes wrong it will usually be in the network call or making a wrong assumption about a JSON object.
Unit Tests are not good for these network-related and i/o related tasks, otherwise, they won't be called unit tests.
SO I am trying to gather the point of Unit Tests in my case. Why would I test if an Android button can click or an EditText can see what I type? I just don't understand the utility of implementing these tedious tests
private void initElements(){
placeButton = (Button) findViewById(R.id.currplace);
placeButton.setText(MainActivity.this.getString(R.string.findingLocation));
placeButton.setEnabled(false);
selectplaceLayout = (LinearLayout)findViewById(R.id.selectplaceLayout);
selectplaceLayout.setVisibility(View.GONE);
splash = (RelativeLayout)findViewById(R.id.splashbg);
infoLayout = (LinearLayout)findViewById(R.id.infoLayout);
}
if this above method passed, which all my activities run in onCreate, then I know the app works. A unit test of this would be a redundant time-consuming thing to create. Time-consuming because I am not familiar with all the methods in the jUnit and Android testing framework.
So, long story short, what's the point? Is there a particular way I should be thinking about these tests? All examples and tutorials I've seen so far only talk about the simplest examples, for the sake of brevity, but I cannot think of any practical uses for unit tests in a predominately client-server app.
What am I expected to discover by accessing the android views that I already know I declared and initialized? I must be thinking about this in a too limited way
so, insight appreciated
There are lots of facets in your question, but to my opinion - you probably don't need unit-tests in your project.
Unit tests really shine when you need lots of business logic to your project. In this case you probably want to divide your application into multiple layers (say, 3-tier architecture) to, among other, add some natural isolation for business-logic layer and cover it with safety net of unit tests.
This safety net covers your ass during refactor of the business layer, and that's one of the main things you what from unit tests (TDD can offer some nice extra side effects though).
However, it's not all unicorns and rainbows and unit-test may cost, and sometimes they cost a lot. Good unit tests are isolated (i.e. deal with small chunks of code). This means that you have to add layers of abstraction in order to put your classes under the test.
This may have positive affect on your system or negative one. Layering makes your system more flexible with cost of increased complexity.
Having that said - the value of the unit-tests is proportional to the amount of abstract business-logic you are going to introduce in your project. You may think of it also this way - if it is overkill to add abstract layers to your architecture - don't add unit-tests - they will only make things more complicated (architecture and build wise).
Based on your description - your typical app tend to be pretty much presentation layer for some external server-side. It does not that much except presenting information on android handset and transforms user actions to commands to server-side where main business logic gets done (controlling).
With this approach most of the code you probably write is related to "how to display this and that" or "how to signal server in this and that case". This sort of code is obviously heavily depend on platform and this mean that if you do want to put it under test you'll have to mock lots and lots of Android specific code\behavior.
Now, Android is somewhat specific platform. It was designed to be both performance optimized and allow developers to start and produce apps quickly. Often this means some amount of "swiss-knife" classes you have use\extend and generally this speeds up writing code, but mocking those classes can become a real hell. Not to mention that you have to have understanding of how platform works under the hood to make those mock useful. In other words overhead from making those test is going to be high.
Another thing that is wrong with testing presentation layers is that they tend to change much more dynamically than business layers. And, of course this mean that you'll have to refactor thee tests which adds even more overhead.
I have to say one thing about various utility/helper classes though. Even if these classes are belong to presentation layer and do depend Android code, but do some rather non-trivial logic and it is easy to mock and write unit tests for them, it might actually be a good idea to do this. However, if you do have lots of such code - this is might be a signal that you haven't designed your architecture/layering well, and need to rethink what you are doing.
In the end to answer your question you have to answer these questions first:
Will it be overdesign to add abstract layer that is separated from the platform to your application (seems like in your case it will)? If yes - do not use unit-tests - they will only slow you down. If no - do use them.
Are you going to refactor a lot? If that's large project with lots of code and thus maintenance - you probably will, so invest in layering and unit-tests (but, at a glance, it does not seem that this is your case). If that is not your case - do not bother with unit-tests and go fast.
Do you need to mock platform a lot to write your unit tests? If yes (seems to be your case) - don't write unit tests - they do not worth the effort.
Hope this will help.
UTesting in Android generally takes relevance when you are using some layering with a good architecture. Nowadays the most popular is Clean Arch, which is all about maintainability and testability. Every part of the architecture has exactly one purpose. We just need to specify it and check that it actually does its job every time.
When testing use cases we should test that use case calls correct methods in repositories or executes other use cases. We should also test that use case returns proper callback.
When testing repositories, you should arrange DAOs – make them return or receive some dummy data, and check that repository is handling the data in a proper way.
When testing mappers (converters), specify input to the mapper, and exact output you expect from the mapper, then assert they are equal. Do the same for services, parsers etc.
Leaving the architecture besides any good modular and decoupled design will contain business logic in functions and classes, and if those follow single responsibility principle (they should), then likely should be tested.
Think about testing before and during coding. That way you can write testable and decoupled code. Use your tests as class specification, and if possible write them before the code.
Examples and expanded info: https://five.agency/android-architecture-part-5-test-clean-architecture/
from Android.Docs
For testing Android apps, you typically create these types of automated unit tests:
Local tests: Unit tests that run on your local machine only. These tests are compiled to run locally on the Java Virtual Machine (JVM) to minimize execution time. Use this approach to run unit tests that have no dependencies on the Android framework or have dependencies that can be filled by using mock objects.
Instrumented tests: Unit tests that run on an Android device or emulator. These tests have access to instrumentation information, such as the Context for the app under test. Use this approach to run unit tests that have Android dependencies which cannot be easily filled by using mock objects.
Note: Unit tests are not suitable for testing complex UI interaction events. Instead, you should use the UI testing frameworks, as described in Automating UI Tests.
I'm new to Android testing and I`d really appreciate if some of you could help me with that.
I'm using robotium as automation testing framework (so far so good), but I have no idea how I use mockito or Easy Mock to add some mocks to my tests. I'm really stuck with that. Can someone give me some simple example on how to achieve this?
Thanks in advance
Short Answer/opinion
I don't recommend using Mockito for Android unit testing. The Android environment feels too complex to mock. The basic approach for Android unit tests is to run them within the emulator. Thus many of the container classes are already present and need not be mocked.
Long Answer
I also am relatively new to the world of Android unit testing. I have long written server-side unit tests and found Mockito to be one of the best tools around to simplify unit testing. Mockito is very helpful in mocking the behavior of complex objects. This helps to break any dependencies that your code-under-test may have on containers (e.g. servlet container or OSGI container), or on other complex collaborators (e.g. database connection classes).
This sort of mocking works well when your containers/collaborators have well-defined interfaces.
A couple months back, I decided to try Mockito with Android development. I found that Mockito does work if you have at least 1.9.5 and dexmaker. Dexmaker handles runtime byte-code generation for Android's Dalvik VM.
The first thing I tried in my very first test was to mock android.content.Context, and I found that is was HARD. First I tried to mock only the methods that I called directly, but then I found that these called into other methods which had dependencies on application resources, ... Eventually the mocking got so complicated that it defeated the purpose of using Mockito in the first place.
So I gave in and started using the Android unit test helper classes (AndroidTestCase, ActivityUnitTestCase, ...). I was discouraged that I now had to rely on the emulator which meant SLOW test execution. Perhaps Mockito still has a place in this type of test. It might be useful for mocking things like external data sources.
Anyways, this is just my 2 cents.