Robolectric + Mockito - android

Trying to build android unit tests using Robolectric. Everytime I need to mock a method that belongs to my project it becomes slightly heavy to create a Shadow class. I think using Mockito in such cases would be much easier and lighter.
But when I try to use Mockito methods I get an error java.lang.IllegalArgumentException: dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system property)
In order to fix this I believe the dexcache property needs to be set by calling
System.setProperty("dexmaker.dexcache",getInstrumentation().getTargetContext().getCacheDir().getPath());
But I don't know getInstrumentation can be called while in Robolectric. Pls suggest a recommended approach to mock the methods of my Project in Robolectric.

You can use Mockito with Robolectric; however, you need to make sure you're adding the "normal" Mockito dependency, and not the Mockito-Android or dexmaker dependency.
Mockito works by generating classes; on desktop JREs such as your unit test environment, that means generating Java CLASS files, but on Android devices and emulators that means generating DEX files. However, Mockito will opportunistically use DexMaker if it exists on the classpath, even when running outside of an emulator as Robolectric unit tests do. Adjust your dependencies to ensure that dexmaker is not included, which will avoid any problems with dexmaker or dexcache.

A good way to separate your thinking about Robolectric and Mockito is
Mockito: Mock and verify your Java classes / non Android framework dependencies
Robolectric: Provides the TestRunner and working Android Framework elements where needed, e.g. Intent, Context
Build.gradle dependencies
dependencies {
...
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
testCompile 'org.mockito:mockito-core:1.10.19'
}
Robolectric test runner
#RunWith(RobolectricTestRunner.class)
public class ExampleUnitTest {
#Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
Happy testing!

Related

JUnit5 not generating test-result TEST-*.xml that JUnit4 used to

When I used JUnit4 in my projects it seemed that each time a test ran, it would generate a TEST-*.xml report in app/build/test-result. Jenkins would use these XML reports to display failing and passing tests on each build.
I've replaced JUnit4 with JUnit5 with the following in build.gradle:
testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.2"
When running tests with JUnit 5, I'm no longer seeing these TEST-*.xml files being generated. As soon as I drop back to JUnit4, they are.
Is this no longer available in JUnit5 or is there something I have to set on each test in order to get these XML reports?
Found the solution. In order for the XML reports to be generated for each test you need to include the following in your build.gradle:
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.2'
As well as:
tasks.withType(Test) {
useJUnitPlatform()
}
This other post may also be of use to others: JUnit5 integration tests with Gradle 4.6

Using Dagger2 with flavors and androidTest source set

I am attempting to write instrumentation tests for an app that uses Dagger2. The app has several build types and one of them is called automation. The automation build type is also set as the testBuildType in the build.gradle.
The activity I'd like to test has a Presenter injected that depends on a Repository. What I'd like to do is inject a real repository when I'm building any build type except for automation and then when I build the automation build variant I'd like to inject a mock Repository.
In my androidTest source set I've created a MockComponent and a MockModule which create mock a mock version of the Repository. What I figured I would be able to do is build an instance of MockComponent and use it to provide a Mock Repository. The problem seems to be that if MockComponent and MockModule are in the androidTest source set then Dagger never generates the DaggerMockComponent class when I build. If I move MockComponent and MockModule to the automation source set then Dagger does generate the classes however then I'm in a position where I want to add an inject method to MockComponent so that I can inject an object into my activity test class but MockComponent can't get see the activity test class because it's in the android source set.
Any ideas why Dagger won't generate the DaggerMockComponent class when it's in the androidTest source set?
The issue ended up being that in my build.gradle file I needed to include a dependency for the androidTest source set. Normally you use
androidTestCompile "com.package.version:1.2.3"
But for dagger you have to use apt so the line looks like:
androidTestApt "com.google.dagger:dagger-compiler:$rootProject.ext.daggerVersion"
The really confusing thing about this was that since I am using a build type (automation) for my testBuildType I was able to add dagger code to the automation source set and dagger could compile it b/c it wasn't in the androidTest source set. Then I tried to add the dagger code to the androidTest source set and suddenly it was like it was invisible to the dagger compiler b/c it would never generate the dagger classes for the components that were specified in the androidTest source set.

Mockito mocks run actual Android code in Lollipop or greater

So I have a Database class that has a dependency that extends SQLOpenHelper and I am testing using Android instrumented tests and Mockito to mock dependencies. We are noticing that Mockito isn't actually mocking the implementations when doing Mockito.mock(class) instead the actual code is running and throwing null pointer exceptions as we would expect. On API 19 devices the tests run as expected and the mocks work correctly.
Does anyone have any suggestions or things to try? I've tried real devices and emulators with similar results. Could this be a Mockito issue, or a dex-maker issue? I haven't found any information while searching for it.
After some more testing any class I mock with Mockito actually just uses the implementation. Here are my dependencies
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
Note: This is also in a library module if that makes any difference.
So getting rid of our old Mockito dependencies and dexmaker and using the new: Mockito-android
Fixed our issues

Confused about testCompile and androidTestCompile in Android Gradle

I'm new to testing world and even more to Android testing world. While doing research on Robolectric that aids with tests on android one thing confuses me the most. Sometimes on the web I see people using testCompile keyword in dependencies of the gradle build script when referencing Robolectric while others use androidTestCompile. Certainly both can't be valid?
Can somebody explain the difference between the both and which of these should be the one used when using Robolectric?
Simply testCompile is the configuration for unit tests (those located in src/test) and androidTestCompile is used for the test api (that located in src/androidTest). Since you are intending to write unit tests, you should use testCompile.
Update: The main distinction between the two is the test sourceset runs in a regular Java JVM, whereas the androidTest sourceset tests run on an Android device (or an emulator).
To answer your question - Use testCompile for robolectric
why, because robolectric runs on the JVM mocking all the android device behaviour.
testCompile and androidTestCompile are "by convention" android folders which gradle uses while running tasks provided by android plugin.
androidTestDebug picks tests from androidTest folder,
testDebug picks tests from test folder,
Again these are only by convention folders you can give source sets for these configurations
Note: espresso is such an awesome library try to move away from robolectric :)
//unit testing
testCompile 'junit:junit:4.12'
The above code is a dependency of JUnit 4 in build.gradle file in android studio.
You see that it has testCompile, beacuse JUnit runs on JVM and does not require a device or emulator to run. That also means that JUnit tests will not require the application context to run and if they require we would need to "MOCK" them.
//Insturmented Unit Testing
androidTestCompile('com.android.support.test:runner:0.5', {
exclude group: 'com.android.support', module: 'support-annotations'
})
Now we see androidTestCompile here, because this time we intend to use the device or emulator for tests, that is Instrumentation testing. For beter clarification I would suggest to read from developer.android.com
To add Dependency for JVM testing or Unit testing (testing those rely only on java environment, we don’t need any android environment).
We Use testCompile directive. Example:
dependencies {
testCompile gradleTestKit()
}
To add Dependency for Instrumentation test (Those testing mainly rely on Android environment), we use the androidTestCompile directive.

Testing using Mockito

Apologies for what may seem an idiotic post.
How do you run Mockito on the newest version of Android Studio SDK?
and can you run multiple tests using Mockito using the Android Studio platform?
I've used Mockito on Eclipse and ran as much as 6 tests in the same window. But I'm trying to figure out how to do this on the Android Studio platform and I cannot find any website or tutorial with an answer.
Android Studio 1.1 now has built-in support for unit testing. From Unit testing support - Android Tools Project Site:
Unit tests run on a local JVM on your development machine. Our gradle plugin will compile source code found in src/test/java and execute it using the usual Gradle testing mechanisms. At runtime, tests will be executed against a modified version of android.jar where all final modifiers have been stripped off. This lets you use popular mocking libraries, like Mockito.
You will have to specify your testing dependencies in the build.gradle file of your android module. For example:
dependencies {
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:1.9.5"
}
The page also contains a step-by-step guide for setting up Android Studio for unit testing, including creating a separate directory for unit tests:
Create a directory for your testing source code, i.e. src/test/java. You can do this from the command line or using the Project view in the Project tool window. The new directory should be highlighted in green at this point. Note: names of the test source directories are determined by the gradle plugin based on a convention.
I'm currently working on a project using junit 4.12 and Mockito 2.0.5 beta for unit testing in Android Studio 1.1, and haven't had any issues:
dependencies {
// ...
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:2.0.5-beta"
}
As far as running multiple tests at the same time, do you mean test cases? Test classes? Test suites? Please clarify, and I'll update my answer, if needed.
Open your app/build.gradle file in your application and add mockito to the dependencies, if dependencies isn't there you can go ahead and create it.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile 'org.mockito:mockito-core:1.10.8'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.1'
}
Then in your unit tests, just create a mock object as you normally would:
http://site.mockito.org/#how
Unit tests should be under the app/src/androidTest/ folder.
I can verify that the accepted answer is correct however just to further to the answer, there will be an androidTest folder alongside your main folder. Normally you would use the androidTest folder for instrumentation tests. Just make sure that under the build variants panel, the Test Artifact: is selected to be "Unit Tests" otherwise the testCompile in build.gradle will not work. It took me a while to figure this part of out.
Hope it helps.

Categories

Resources