How to create a new Bundle object? - java

I'm trying to use Firebase Analytics for an Android application, and in order to log events I've followed https://firebase.google.com/docs/analytics/android/events. That is, in order to send my event, I have to create a new Bundle object (which I create by using the default constructor) and I call the logEvent function of Firebase Analytics. While testing my development with a simple unit test, I realized that there's no content set in the bundle, which makes me wonder if any information is sent at all. Incidentally, it also breaks my test case.
Here's a simplified test case that shows my problem:
import android.os.Bundle;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class SimpleTest {
#Test
public void test() {
Bundle params = new Bundle();
params.putString("eventType", "click");
params.putLong("eventId",new Long(5542));
params.putLong("quantity", new Long(5));
params.putString("currency", "USD");
assertEquals("Did not find eventType=click in bundle", "click", params.getString("eventType"));
}
}
This test case fails with the following message:
junit.framework.ComparisonFailure: Did not find eventType=click in bundle
Expected :click
Actual :null
Would someone know where the problem is? That is, how do I create a Bundle object from zero and populate it correctly so that I can use it in a unit test like this?
Please bear with me on this one as I'm discovering the specifics of the Android environment as we speak.

As pointed out by Tanis.7x in a comment to my original question, all Android framework classes need to be mocked as the android.jar used for running unit tests is empty as documented here.
Here's an updated version of my original simplified test case:
import android.os.Bundle;
import org.junit.Test;
import org.mockito.Mockito;
import static junit.framework.Assert.assertEquals;
public class SimpleTest {
#Test
public void test() {
Bundle bundleMock = Mockito.mock(Bundle.class);
Mockito.doReturn("click").when(bundleMock).getString("eventType");
Mockito.doReturn(new Long(5542)).when(bundleMock).getLong("eventId");
Mockito.doReturn(new Long(5)).when(bundleMock).getLong("quantity");
Mockito.doReturn("USD").when(bundleMock).getString("currency");
assertEquals("Did not find eventType=click in bundle", "click", bundleMock.getString("eventType"));
}
}
The main difference is, that the variables I set earlier with simple getters are now set by using the appropriate functions of Mockito. The code is not as easy on the eyes, but it should allow me to obtain the wanted behaviour.

Try using .equals() to compare strings as assertEquals() also uses the .equal() method for its working.

Related

Android Instrumented Test, Mock Final Classes

How to mock final classes inside Android Instrumented Test cases, that is mocking final classes inside Android Run Time?
(I am using Mockito 2.X)
I have a test case like follows -
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
// This is my app specific NON - Final class
private ShutdownServicesReqSig rebootSig = ShutdownServicesReqSig.newBuilder(ShutDownType.REBOOT_SYSTEM).setReason("test").build();
private PowerManager mockedPowerManager = null;
private Context mockedContext = null;
#Test
public void testRestart() throws InterruptedException
{
mockedContext = Mockito.mock(Context.class);
mockedPowerManager = Mockito.mock(PowerManager.class); // Here is the problem android.os.PowerManager is a Final class in latest Android SDK
// I need to mock it, only then I can use Mockito.verify() on PowerManager
Mockito.when(mockedContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mockedPowerManager);
assertTrue(executor.requestShutdown(rebootSig));
Thread.sleep(1000);
Mockito.verify(mockedPowerManager).reboot(any(String.class)); // Mocking of PowerManager is essential to be sure of method call on PowerManager, using Mockito.verify
Mockito.reset(mockedPowerManager);
}
}
When I am running it as Android Instrumented Test on ART(placing inside - MyApplication\app\src\androidTest), I am getting following error -
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class android.os.PowerManager
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
But, the same code, when I am running as a normal JUnit test, inside JVM (placing inside - MyApplication\app\src\test) it is working perfectly fine.
I need to run it inside ART, as I like to test some of my customized Android Services, and I need to mock final classes like PowerManager, as only then I can use Mockito.verify() on PowerManager, to verify certain method calls on PowerManager.
Help/guides are appreciated.
Mockito 2 has an "opt-in" mechanism to enable mocking of final methods or classes, see here. You enable it via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
(well, that file needs to be in the class path).
If that works for you, perfect. If not, there is probably nothing else you can do.
You see, instrumenting boils down to: manipulating byte code. Typically, it doesn't work out to use more than one framework doing that.
Meaning: in order to enable that kind of mocking, bytecode needs to be manipulated. And for obvious reasons, getting two different bytecode manipulation frameworks to nicely coexist is a very tough challenge.
Long story short: try that extension mechanism, when it doesn't work you have to step back and ask yourself: what exactly is the final goal I intend to achieve?!
Most likely, you probably shouldn't waste your time trying to mock things running within ART.
In order to mock and spy final classes & methods in Android Integration tests and Android Instrumentation tests, you need to only add the following dependency to your build.gradle file:
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline-extended:2.28.1"
Make sure to remove any other mockito dependency that you are using as an androidTestImplementation.
Also, if you have created a mockito-extensions/org.mockito.plugins.MockMaker file, make sure to delete that either.
This dependecy works for devices running Android P or above.
Refer to these to links for more details on this dependency: Link1, Link2.

Why do I get "Type okhttp3.Call does not have type parameters" when using Retrofit2?

I am trying to follow this tutorial for Retrofit2 Getting Started and Create an Android Client.
The imports are fine
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
and I can follow the tutorial fine except for one thing. I am trying to create the GitHubService Interface and I run into two problems: The Call<V> says that it doesn't take any type parameters and I am also unsure where to put the Contributor class since it's according to the tutorial only declared as static, does that mean it's nested somewhere?
import okhttp3.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface GitHubClient {
#GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
#Path("owner") String owner,
#Path("repo") String repo
);
}
static class Contributor {
String login;
int contributions;
}
I have the Contributor class in a separate file and have it as public.
Also, the Call class does not import automatically in Android Studio, I have to select it manually, but it's the only Call I got (except for Androids phone api)
Please help me with why I get this errors, from what I can see there is no one around with the same thing so I am missing something fundamental.
Accordingly to the compile time error you are getting you did import Call from the wrong package. Please, check your import and be sure that you have
import retrofit2.Call;
everything Retrofit related import should be from the package retrofit2.
On the other hand
Call contributors(
it can't guess what you want to return. A Contributor ? a List<Contributor> maybe? E.g.
public interface GitHubClient {
#GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
#Path("owner") String owner,
#Path("repo") String repo
);
}

PowerMock class not found

For some reason I fail to follow a pretty straight forward PowerMock example.
I included powermock-mockito-1.5.1-full in my classpath, and I try to test a public final method (following this example).
For some reason I am not able to make the import to the PowerMock class.
import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.cleancode.lifesaver.camera.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(android.hardware.Camera.class)
public class CameraTests {
private android.hardware.Camera _cameraMock;
#Before
public void setUp() {
_cameraMock = PowerMockito.mock(android.hardware.Camera.class);
}
#Test
public void releaseCamera() {
ICamera camera = new Camera(_cameraMock);
// Compile error: PowerMock can't be resolved
PowerMock.replay(_cameraMock);
// I also tried PowerMockito.replay(_cameraMock) but that also doesn't exist.
camera.release();
Mockito.verify(_cameraMock).release();
}
}
As the comment explains, the PowerMock class can't be imported from the power mock jar.
It feels like a silly question, but I really can't find anything on the internet.
Where should I be able to find the static class PowerMock? I also used Java Decompile to search the powermock library, no hits on powermock / replay.
The example you are following PowerMock.replay(_cameraMock); is using EasyMock, while you seem to be wanting Mockito. Take a look at this tutorial for mockito & power mock
I suggest you not to create your mock in your setUp() (Before) method, because a mock is very complicated, for example you can tell it exactly how many time it should expect a method is called, if you declare a "general" mock for all your tests it's very difficult to control this behaviour.
maybe (without the code I can only guess) you want that your android.hardware.Camera is called inside your Camera.release() method, am I right? so I whould do like this:
The method you are trying to mock is not static, it's a normal final method. You can try to do this:
android.hardware.Camera mock = PowerMock.createMock(android.hardware.Camera.class);
PowerMock.expect(mock.release());
PowerMock.replay();
ICamera camera = new Camera(mock);
camera.release();
PowerMock.verify(mock);
if inside camera.relase() is not called exactly once the android.hardware.Camera.release() method the test fails.

Java Easymock complains with "java.lang.IllegalStateException: void method cannot return a value" or "no last call on a mock available"

We are using EasyMock for JUnit testing of our Java application inside Eclipse. Using code similar to the below, we found a strange behaviour: when running the full test suite (Eclipse Project -> Run as -> JUnit) one test case fails reproducibly. However when running it standalone it works fine.
Interface:
package de.zefiro.java.easymockexception;
public interface Fruit {
public String fall();
}
Test class:
package de.zefiro.java.easymockexception;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass;
import org.junit.Test;
public class Newton {
private static final Fruit APPLE = createNiceMock(Fruit.class);
#BeforeClass
public static void SetUpClass() {
expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
replay(APPLE);
}
#Test
public void testGravity() {
String target = APPLE.fall();
assertTrue("Missed", target.contains("HEAD"));
}
}
Test suite:
package de.zefiro.java.easymockexception;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(value = Suite.class)
#SuiteClasses( { Newton.class } )
public class ScienceTests { }
Running all tests on the Eclipse project - i.e. both ScienceTests calling Newton as well as Newton directly - produced this exception in the above small example:
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.Easymock.getControlForLastCall(EasyMock.java:175)
There is a similar question here, but it seems to be unrelated.
And in our real testing code (bigger class, but the main actors are identical to the stripped-down example) this exception:
java.lang.IllegalStateException: void method cannot return a value
at org.easymock.internal.MocksControl.andReturn(MocksControl.java:101)
I didn't find an answer either on Google nor here on StackOverflow, but found out myself now, so in the spirit of answering your own questions I'll post my findings below. Worth mentioning is also this post I found, even though it didn't help me in this particular case: EasyMock Cause-Effect Exception Mapping
Putting Breakpoints on the line initializing APPLE and inside SetUpClass() I noticed that APPLE is called exactly once, while SetUpClass is called twice. This is due to the fact that the first reference to Newton creates the class and runs the static initializers, however JUnit calls #BeforeClass for each run of the test. In this case the test is run twice: once as a normal call and once as part of the test suite.
I didn't want to change the logic (i.e. don't use static), but instead changed the static #BeforeClass to a static initialization block:
public class Newton {
[...]
static {
expect(APPLE.fall()).andReturn("Targeting HEAD").anyTimes();
replay(APPLE);
}
// no #BeforeClass needed anymore
[...]
}
This solved the issue in both my simplified test above and in our real test coding.
I didn't find out what the difference was that triggered the different exception message, but the findings were the same - new was called only once, #BeforeClass was called multiple times and failed on the second run. The fix also worked on both.

Mockito Passes but Code Coverage still low

package com.fitaxis.test;
import java.sql.SQLException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.mockito.Mockito.*;
import com.fitaxis.leaderboard.LeaderBoard;
public class LeaderBoardTests {
#Test
public void TestThatDataIsSavedToTheDatabase()
{
LeaderBoard leaderBoard = mock(LeaderBoard.class);
//doNothing().doThrow(new RuntimeException()).when(leaderBoard).saveData();
when(leaderBoard.saveData()).thenReturn(true);
boolean res = leaderBoard.saveData();
verify(leaderBoard).saveData();
Assert.assertTrue(res);
}
}
I have used mockito to mock a class, but when I use code coverage it does not detect that the method as been called. Am I doing something wrong? Please help!
It looks like you're mocking out the only call you're making to production code.
In other words, your test says:
When I call saveData(), fake the result to return true
Now call saveData() - yay, the result was true!
None of your production code is being calls at all, as far as I can see.
The point of mocking is to mock out dependencies from your production class, or (sometimes, though I prefer not to) to mock out some methods of your production class that the code you're actually testing will call.
You should probably be mocking out the dependencies of Leaderboard rather than Leaderboard itself. If you must mock out saveData(), you should be testing the methods that call saveData()... check that they save the right data, that they act correctly when saveData() returns false, etc.
if i understand your question correctly :
because you are mocking LeaderBoard. that means that you are not testing it.
if you want to test LeaderBoard, you should test the actual class not the mocked one.
let say you want to test class A but this class depends on B and B is a bit difficult to instantiate in testing environment(for any reason). in such cases you can mock B.
but here is your case you are mocking class A itself. that means you are not testing anything.
add runner class as MockitoJUnitRunner, please refer the below sample code
import org.mockito.junit.MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MockitTesterClass{
#Mock
private TestService testServiceMock;
}
now the code coverage will increase

Categories

Resources