Mocking Google Analytics v4 - android

I'm trying to test my code that depends on Google Analytics SDK v4.
Specifically I'm trying to mock com.google.android.gms.analytics.Tracker with Mockito.
Tracker tracker = Mockito.mock(Tracker.class); yields this error.
Are there any approaches to take? The only thing I can think of is to create my own wrapper.

I believe the code snipped at fault is Tracker.class - as this will instantiate the class, which in turn throws the VerifyError. This is not an issue with your code, but is a limitation of Google Play Services. The issue has been reported in the Robolectric project and here.
I used the solution provided in the second link by SuperJugy, by inserting the following to the bottom of my Gradle build file:
tasks.withType(Test) {
test {
// set JVM arguments for the test JVM(s)
jvmArgs '-XX:-UseSplitVerifier'
}
}
To get it working in Android Studio I had to add the VM Option -noverify to my test build configuration.
I think you may be able to work-around the problem using a wrapper, so long as the wrapper code never instantiates the Tracker class. However this may not be easy (or possible?), please let me know if end up going down this path and succeed!

Related

How do i resolve this warning junit5 throws when i run Parameterized tests?

I get this warning in my test console when i run test cases annotated with #ParameterizedTest
"org.junit.platform.launcher.core.InternalTestPlan add
WARNING: Attempt to modify the TestPlan was detected. A future version of the JUnit Platform will ignore this call and eventually even throw an exception. Please contact your IDE/tool vendor and request a fix (see https://github.com/junit-team/junit5/issues/1732 for details)."
How do i fix it?
According to the link in the error message, it would seem that:
IntelliJ IDEA is affected, fix is on its way: JetBrains/intellij-community#1030
Following that link, it seems that it should be fixed in the 2019.1 release of IntelliJ.

Is Android Gradle Plugin test apk builder automatically multidexing my test apk? If so, why is this generating "NoSuchMethodError"

This all started with this error when running instrumentation tests:
java.lang.NoSuchMethodError: No static method closeQuietly(Ljava/net/ServerSocket;)V in class Lokhttp3/internal/Util; or its super classes (declaration of 'okhttp3.internal.Util' appears in /data/app/com.example-vKdPJoTLl49ntRbZfsRBqQ==/base.apk!classes2.dex)
at okhttp3.mockwebserver.MockWebServer$2.execute(MockWebServer.java:333)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
I went looking into the generated test.apk to see what was present/missing in dex files.
First thing I noticed is that the test apk has two .dex files. Why? I'm not using multidex (and IIRC multidex doesn't work on test apks anyways). I then added up the two "referenced method counts" and sure enough I'm over the 65k limit. So is AGP auto-multi-dexing my test apk?
Furthermore I see the "missing" method in the first dex.
Why is it listed as a "reference" not a "defined" method? It's not like there is an OkHttp Util class provided by the framework.
In the initial crash, it said it can't find method in classes2.dex. Why is it looking in classes2.dex? Why not look in both?
I'm keeping everything in my test apk (using proguard but keeping everything) (maybe this explains the +65k ref methods). So why is this getting stripped/screwed with in the first place.
UPDATE:
It turns out this method was needed in my app .apk (not the test .apk). When I updated my proguard rules for the app apk everything worked. I still don't know why this class is needed in-app?
java.lang.NoSuchMethodError:
No static method closeQuietly(java.net.ServerSocket) in class okhttp3.internal.Util;
method closeQuietly(java.net.ServerSocket) might not be in use.
to explicitly keep it:
-keep class okhttp3.internal.Util {
public static void closeQuietly(java.net.ServerSocket);
}
I don't know how I didn't know this but apparently multidex is enabled by default on API 21+
https://developer.android.com/studio/build/multidex#mdex-on-l
Therefore, if your minSdkVersion is 21 or higher multidex is enabled
by default, and you do not need the multidex support library.
So yeah, this is normal. What might be happening is that the class is just not in the first dex file.

Test - FirebaseApp is not initialized in this process

I'm trying to run a test with Robolectric and it has an integration with Firebase. I have a project MyProject - Test that I'll be using to run the tests in a real instance of the database.
The problem is that, when running cleanup before test, I have the error:
java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process null. Make sure to call FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(Unknown Source)
at com.google.firebase.database.FirebaseDatabase.getInstance(Unknown Source)
at com.cgbros.silkhub.activity.listener.LoginActivityUnitTest.cleanUp(LoginActivityUnitTest.kt:26) <28 internal calls>
The test file:
https://gist.github.com/augustoerico/e88d3e5b59ae5d023d83c114b8ffa708
(I tried to copy-paste the source here. Failed miserably...)
Any insights on how I can make this work?
Thank you!
Ok, I've figured it out. It's actually a conceptual problem. The problem is that I'm trying to use the Firebase Android SDK to run a test outside of the Android context. I mean, my test is not an Android application, and I'm trying to use the Android SDK. All FirebaseApp.initializeApp() need a Context as a parameter.
So, what I have to do is to find a way to interact with my FirebaseDatabase. I think I can go with firebase-admin, or maybe use this one: https://github.com/bane73/firebase4j
Thank you for taking the time to help me (:
** Update **
I've opted to go with the Firebase REST API https://firebase.google.com/docs/reference/rest/database/
For future reference, I'm giving public full access, by tweaking the rules, so it is easier to write the tests setup and cleanup.
I've had the same problem and fixed it by initializing Firebase in the before step of my unit test:
FirebaseApp.initializeApp(InstrumentationRegistry.getInstrumentation().targetContext)
I also had the same issue a few day ago and i solve it in the same way the error says. You get that error because you're trying to get an instance of Firebase without initialize it. Please add this line of code before you try to get an instance of Firebase like this:
FirebaseApp.initializeApp(this);
Also, as Franks says, please be sure you have the following line of code added in your build.gradle file, as the last line of your entire file.
apply plugin: 'com.google.gms.google-services'
I used the most simple and straightforward approach.
Since you init your Firebase App in your Application, just create a variable there. For example,
//Your Application.class
open var isTestMode = false
onCreate(){
if(!isTestMode){
//Init your Firebase app
}
}
And then in Robolectric Application just extend your application and override the variable. In this case don't forget to provide configuration
#Config(application = TestApplication::class)
I also faced the above issue. Do all plugin download and checks by nuget. But in the end, I found the crashing was due to , Application Package Name not matching the one Assigned in Google Dev.
Application package name must matche the one that assigned in the Google Dev. Console
after add this line and then you get error
FirebaseApp.initializeApp(this);
then you have to do that also
add this line to Gradle (App)
apply plugin: 'com.google.gms.google-services'
add this line to Gradle (Project)
classpath 'com.google.gms:google-services:3.2.1'
also check if no dependncy is missing and make sure you add google-services.json

SecurityProvider in Mockito Tests when run alongside Robolectric

We haven an Android project where we use MockitoTestRunner and RobolectricTestRunner for different kinds of tests.
I have written a set of unit test that are concerned with SSL, thus loading certs/keystores/truststores, etc. For this I used the MockitoJUnitRunner and added the Bouncycastle provider programmatically as such:
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Now, these tests run perfectly fine when run on their own - e.g. when I directly run single methods from the test classes, or run these classes from the Project tree menu, they work just fine.
But when I run said tests along side ANY test which uses the RobolectricTestRunner (such as if I just run all the tests in my project together before committing), I get the following exception:
java.io.IOException: error constructing MAC:
java.lang.SecurityException: JCE cannot authenticate the provider BC
I'm baffled. How will the testrunner used in one test class affect the run of other classes, especially if we use a different test runner?
Additional info:
The exception only occurs once I actually try do do something with the BC provider (e.g. the first time the test tries to load a PKCS12 certificate) - the insertProviderAt(...) call itself seems to pass fine...
Also when I print out the list of providers for each test run, I see that Robolectric already has a BC provider in there, but is still failing when I try to use it.
Also if I don't add the BC provider, the tests still fail with the same error when run in a test suite alongside Robolectric tests. When run alone they fail with java.security.NoSuchProviderException: no such provider: BC, as we're specifying the provider explicitly.
Seems like Robolectric is using its own classloader (that favors its replacements on the Android API), which could be in conflicts with the regular classloader of Mockito.
So for using at the same time the Robolectric and mockito, you may do the following:
Make use of the Robolectric runner. Robolectric uses its own classloader that favors its replacements for the Android API, so it really does need to handle classloading on its own. There's no other way to use Robolecric.
Replace the #RunWith(MockitoJUnitRunner.class) with these alternative methods covering the behaviour of MockitoJUnitRunner:
#Before public void setUpMockito() {
MockitoAnnotations.initMocks(this);
}
#After public void tearDownMockito() {
Mockito.validateMockitoUsage();
}
Maybe it could be a workaround for using the Robolectric classloader and Mockito at the same time.

How to use EasyMock in android

I use easymock-3.2.jar in my android test project.
I find it in its Home:
2013-07-11: EasyMock 3.2 is available. Add #Mock annotations and Android support.
However , I got exception when I use it.
java.lang.NoClassDefFoundError: org.easymock.EasyMock
I googled a lot , and add
dexmaker-1.0.jar
objenesis-1.2.jar
cglib-nodep-2.2.2.jar or cglib-2.2.jar
But the exception still be there.Who can help me?
Thanks a lot.
Put the library
easymock-3.2.jar
dexmaker-1.0.jar
dexmaker-mockito-1.0.jar
in tests/libs. And it will work.
Be careful , it's in tests/libs , not in tests/lib.
It will throw
java.lang.NoClassDefFoundError: org.easymock.EasyMock
if you position them in tests/lib.
The first step is to get EasyMock. You can get the latest version from Easymock’s download page. Choose the latest version and you will get a zip file. You only need easymock-3.2.jar (3.2 will change depending on the version you choose). You will also need dexmaker for Easymock to work on Android. You can get the jar from Dexmaker’s website. Once you have both jar files put them in /tests/libs. Now you have EasyMock available in your tests.
for more detail follow below link
http://ncona.com/2013/11/writing-unit-test-for-android-with-easymock/

Categories

Resources