How to android unit test and mock a static method - java

Hi I really hope you can help me, I feel like I've been pulling my hair out for days.
I'm trying to write unit tests for a method A. Method A calls a static method B. I want to mock static method B.
I know this has been asked before, but I feel Android has matured since then, and there must be a way to do such a simple task without re-writing the methods I want to test.
Here is an example, first the method I want to test:
public String getUserName(Context context, HelperUtils helper) {
if(helper == null){
helper = new HelperUtils();
}
int currentUserId = helper.fetchUsernameFromInternet(context);
if (currentUserId == 1) {
return "Bob";
} else {
return "Unknown";
}
}
Next the static method I want to mock:
public class HelperUtils {
public static int fetchUsernameFromInternet(Context context) {
int userid = 0;
Log.i("HelperUtils ", "hello");
return userid;
}
}
In other languages this is so easy but I just can't make it work in Android.
I've tried Mockito, but it appears static methods aren't supported
HelperUtils helper = Mockito.mock(HelperUtils.class);
Mockito.when(helper.fetchUsernameFromInternet(getContext())).thenReturn(1);
This errors
org.mockito.exceptions.misusing.MissingMethodInvocationException
I've tried Powermock but I'm not completely sure this is supported by Android. I managed to get powermock running using androidCompile in my gradle file but I get this error:
Error:Execution failed for task ':app:dexDebugAndroidTest'. com.android.ide.common.process.ProcessException:
Not to mention PowerMockito.mockStatic(HelperUtils.class); Doesn't return anything, so I don't know what to pass into my getUsername method!
Any help would be so very much appreciated.

Static methods aren't related to any object - your helper.fetchUsernameFromInternet(...) is the same (but a bit confusing) as HelperUtils.fetchUsernameFromInternet(...) - you should even get a compiler warning due to this helper.fetchUsernameFromInternet.
What's more, instead of Mockito.mock to mock static methods you have to use: #RunWith(...), #PrepareForTest(...) and then PowerMockito.mockStatic(...) - complete example is here: PowerMockito mock single static method and return object
In other words - mocking static methods (and also constructors) is a bit tricky. Better solution is:
if you can change HelperUtils, make that method non-static and now you can mock HelperUtils with the usual Mockito.mock
if you can't change HelperUtils, create a wrapper class which delegates to the original HelperUtils, but doesn't have static methods, and then also use usual Mockito.mock (this idea is sometimes called "don't mock types you don't own")

I did this way using PowerMockito.
I am using AppUtils.class, it contains multiple static methods and functions.
Static function:
public static boolean isValidEmail(CharSequence target) {
return target != null && EMAIL_PATTERN.matcher(target).matches();
}
Test case:
#RunWith(PowerMockRunner.class)
#PrepareForTest({AppUtils.class})
public class AppUtilsTest {
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(AppUtils.class);
PowerMockito.when(AppUtils.isValidEmail(anyString())).thenCallRealMethod();
}
#Test
public void testValidEmail() {
assertTrue(AppUtils.isValidEmail("name#email.com"));
}
#Test
public void testInvalidEmail1() {
assertFalse(AppUtils.isValidEmail("name#email..com"));
}
#Test
public void testInvalidEmail2() {
assertFalse(AppUtils.isValidEmail("#email.com"));
}
}
Edit 1:
Add following imports:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
Hope this would help you.

You can use mockito latest version i.e 3.4.+ which allows static mocking
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#48

Here are some solutions:
Modify your static method as a non-static method or wrap your static method with a non-static method, and then directly use Mockito to mock the non-static method in the Android Test.
If you don't want to change any original code, you can try to use a dexmaker-mockito-inline-extended to mock static methods and final methods in the Android Test. I successfully mocked the static methods with it. Check this
solution.
Use a Robolectric in the Unit test and then use PowerMock to mock the static methods in the Unit Test.

Related

Refactoring static mocks in Mockito 3.4

I have a Jupiter based UnitTest in a java project where I need to mock some static methods of an external utility. Mockito 3.4 allows for mocking static methods, so no need for PowerMock any more. We all use static mocks by defining them in a try(){} block and overwriting methods on those static mocks inside the block. All fine, but things sometimes get annoying when you have to implement a non trivial mocking cascade. Which is especially annoying of you have to do that in several test cases inside your test class.
class ClassA {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassB {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassC {
public static void methodA() { ... }
public static void methodB() { ... }
}
class ClassX {
public int doSomething() {
// does something using static methods from classes ClassA, ClassB, ClassC
return 3;
}
}
A test class might (roughly) look like that (please excuse typos and nonsense, this is only meant as a demonstration, this is not working code):
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
MockedStatic<ClassB> classBMockStatic = Mockito.mockStatic(ClassB.class);
MockedStatic<ClassC> classCMockStatic = Mockito.mockStatic(ClassC.class)) {
// this is a block where static methods get overwritten, also some mocks are created
// this code does not make sense, it is just to demonstrate the issue of non trivial mocking scenarios
// situations like this often arise when mocking building patterns for example
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodA).thenReturn(classCMock);
// and so on and so on, you get the idea
result = classX.doSomething();
}
assertThat(result).equals(3);
}
Typically the question arises if this cannot be refactored to implement the mocking cascade only once. And use it in several test cases. I tried that, I was surprised to find that some of my overwritten methods worked as expected, but not all. I failed to find a working solution:
// THIS DOES NOT WORK
#Test
void test_doSomething() {
int result = 0;
ClassX classX = new ClassX();
try (MockedStatic<ClassA> classAMockStatic = createStaticMockA();
MockedStatic<ClassB> classBMockStatic = createStaticMockB();
MockedStatic<ClassC> classCMockStatic = createStaticMockC()) {
result = classX.doSomething();
}
assertThat(result).equals(3);
}
private MockedStatic<ClassA> createStaticMockA() {
MockedStatic<ClassA> classAMockStatic = Mockito.mockStatic(ClassA.class);
classAMockStatic.when(ClassA::methodA).thenReturn("fooA");
ClassB classBMock = mock(ClassB.class);
when(classBMock.methodA()).thenReturn("barA");
classAMockStatic.when(ClassA::methodB).thenReturn(classBMock);
return classAMockStatic;
}
private MockedStatic<ClassB> createStaticMockB() {
MockedStatic<ClassB> classAMockStatic = Mockito.mockStatic(ClassB.class);
ClassB classBMock = mock(ClassB.class);
when(classBMock.someMethodA()).thenReturn("aaa");
when(classBMock.someMethodB()).thenReturn("bbb");
when(classBMock.methodA()).thenReturn("barA");
classBMockStatic.when(ClassB::methodA).thenReturn(classBMock);
return classBMockStatic;
}
private MockedStatic<ClassC> createStaticMockC() {
MockedStatic<ClassC> classAMockStatic = Mockito.mockStatic(ClassC.class);
ClassC classCMock = mock(ClassC.class);
when(classCMock.someMethodA()).thenReturn("abc");
when(classCMock.methodB()).thenReturn("barC");
classCMockStatic.when(ClassC::methodA).thenReturn(classCMock);
return classCMockStatic;
}
So this looks cleared up, but does not work.
I know that I obviously could just extract the mocking section into a method and call that first in the try block. But that separates the static setup from the mock generation. And it is not as clean as my idea.
Yes, I tried implementing an execution method which accepts a lambda holding the code actually meant to be executed. So that the try(){} block gets stowed away into a method, leaving only the call to that method with a lambda in the test case. Works, but is hard to read and to understand. Not a good solution in my experience.
And yes, I also know that one should try to refactor production code so that it is easier to mock it. Sometimes that is simply not possible (read: external dependencies).
So what are my questions here?
does anyone have an idea how to achieve a clean, refactored look which actually works?
can anyone explain to me why some of the overwritten methods work as expected while others don't? I know, all the examples on the internet demonstrate that you use the straight approach, but the examples are obviously showing trivial situations.
is it really true that no one else is annoyed by that situation of have to setup the mock cascade exactly where it confuses? And that you have to reimplement it for each test case?
As Tim Moore suggests, if you have:
class StaticUtil {
public static void foo() { ... }
}
You can introduce an interface and an implementation to inject into your clients:
interface Util {
void foo();
}
class DefaultUtil {
public void foo() {
StaticUtil.foo();
}
This makes writing tests simpler as you can just mock Util in the normal way.

Testing util class with method dependency [duplicate]

This question already has answers here:
PowerMock, mock a static method, THEN call real methods on all other statics
(2 answers)
Closed 5 years ago.
I have a utility class that I need to do some unit testing, but within this utility class I have methods that depend on others in that same utility class.
For that I'm using the following dependencies:
jUnit:4.12
Mockito: 2.8
Powermock: 1.7
As it's already evident that I am using Java to perform my code.
Now go to the example code:
public final class AppUtils {
private AppUtils () {
throw new UnsupportedOperationException("This class is not instantiable.");
}
public static int plus(int a, int b) {
return a + b;
}
public static float average(int a, int b) {
return ((float) AppUtils.plus(a, b)) / 2;
}
}
And the unit test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({AppUtils.class})
public class AppUtilsTest {
#Test
public void testPlus() { //This test must be good.
assertEquals(6, AppUtils.plus(4, 2));
}
#Test
public void testAverage() {
PowerMockito.mockStatic(AppUtils.classs);
when(AppUtils.plus(anyInt())).thenReturn(6);
assertEquals(3f, AppUtils.average(4, 3), 1e-2d);
}
}
That way I did my unit test, but this throws me an error because it tells me that the expected result does not correspond to the actual one.
expected: 3.000f
actual: 0
This is because PowerMock by using the mockStatic() method replaces all static implementations for your defines, but if you do not define the result of one static method then it returns 0.
If anyone can help me, I thank you.
UnitTests verify the public observable behavior of the code under test.
The public observable behavior of the CUT includes the return values and the communication with its dependencies.
This means that you treat that other methods as if they where private, just looking at the outcome of the method called.
BTW:
There is no such rule that "utility classes" (in the sense that they provide basic or common functionality) must have static methods only.
That's just a common misconception driven by the habit to name classes with only static methods "utility classes".
It is absolutely OK to make all your utility methods non static and instantiate the class before using it.
Dependency Injection (and not the Singelton Pattern) will help you to have only one instance used all around your program...

mock method is not getting called - java

I am new to Mockito, please help in understanding the basic.
According to me above code is supposed to print 5 when mocked.add(6,7) gets called , but add() method is not getting called and the code prints 0.. why ? any solution for this code ?
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
class Calc{
int add(int a,int b){
System.out.println("add method called");
return a+b;
}
}
class MockTest{
public static void main(String[] args) {
Calc mocked=mock(Calc.class);
when(mocked.add(2,3)).thenReturn(5);
System.out.println(mocked.add(6,7));
}
}
In order to get result of 5, you have to pass the exact params as when you set up the when..then. Otherwise mockito will return a 'default' value (which is 0 for integer:
What values do mocks return by default?
In order to be transparent and unobtrusive all Mockito mocks by
default return 'nice' values. For example: zeros, falseys, empty
collections or nulls. Refer to javadocs about stubbing to see exactly
what values are returned by default.
If you want to return 5 for any integer then use:
when(mocked.add(Mockito.any(Integer.class),Mockito.any(Integer.class))).thenReturn(5);
A "mock" is just an empty dummy object that simulates behaviour of a "real" object. If you define a behaviour such like when(mocked.add(2,3)).thenReturn(5); you specifically tell this mock what to do, when it receives those exact values.
mocked.add(6,7) will return 0 at that point, since you haven't defined its behaviour for those values and therefore uses a default value. So if you want to cover all possible inputs, you can go with the solution #MaciejKowalski posted and use the generic matchers like Mockito.any(Integer.class).
Still I believe it is not clear how to correctly handle mocks. Mocks are a way of providing external dependencies to a system-under-test without the need to set up a whole dependency tree. The real methods inside that class are usually not called. That's what something like when(mocked.add(2,3)).thenReturn(5); means. It tells the mock to behave like the real dependency without actually having it at hand.
An example could look like this:
public class TestClass {
private ExternalDependency dep;
public void setDep(ExternalDependency dep) {
this.dep = dep;
}
public int calculate() {
return 5 + dep.doStuff();
}
}
public class ExternalDependency {
public int doStuff() {
return 3;
}
}
Now in your test code you can use mocks like this:
#Test
public void should_use_external_dependency() {
// Aquire a mocked object of the class
ExternalDependency mockedDep = Mockito.mock(ExternalDependency.class);
// Define its behaviour
Mockito.when(mockedDep.doStuff()).thenReturn(20);
TestClass sut = new TestClass();
sut.setDep(mockedDep);
// should return 25, since we've defined the mocks behaviour to return 20
Assert.assertEquals(25, sut.calculate());
}
If sut.calculate() is invoked, the method in ExternalDependency should not be really called, it delegates to the mocked stub object instead. But if you want to call the real method of the real class, you could use a Spy instead with Mockito.spy(ExternalDependency.class) or you could do that with when(mockedDep.doStuff()).thenCallRealMethod();

Call Variable length argument method in abstract class when using Mockito spy on subclass throws exception

I use Mockito 1.8.0 so I do not have AnyVararg. Upgrading to later version of Mockito is not on cards from my team at the moment. So please bear with me.
What the class looks like:
public abstract class Parent {
public void someMethod(String a, String b)
{
//.....
}
public void foo(String a, String... b)
{
//.....
}
}
public class Child extends Parent{
public void bar() {
someMethod(a,b);
foo(a,b,c);
methodToFailUsingSpy();
}
}
Unit tests
#Test
public void someTest() {
private spyOfChild = //initialize here;
doReturn("Something")).when(spyOfChild).methodToFailUsingSpy();
/* Tried using this, but did not help.
doCallRealMethod().when(spyOfChild).foo(anyString());
*/
spyOfChild.bar();
}
Problem -
When the spy sees someMethod(), it calls the real method in the abstract class. But when it sees foo(), it tries to find a matching stubbed method i.e control goes to Mockito's MethodInterceptorFilter, since it is not able to find a mock, it throws java.lang.reflect.InvocationTargetException.
I do not want foo() to be mocked. I want the real method to be called like it happens in someMethod(). Can someone explain if it is because of using method with variable length arguments with a spy?
This is a bug in Mockito.
https://groups.google.com/forum/#!msg/mockito/P_xO5yhoXMY/FBeS4Nf4X9AJ
Your example is quite complicated, to reproduce the problem is very simple:
class SimpleClass {
public String varargsMethod(String... in) {
return null;
}
public void testSpyVarargs() {
SimpleClass sc = Mockito.spy(new SimpleClass());
sc.varargsMethod("a", "b");
}
}
Even this will produce the error you describe, and the workaround suggested in the link doesn't work for me.
Unfortunately to get around this you will need to upgrade Mockito. Changing to version 1.9.5 makes the above run fine, plus you get the varargs matchers as you say (although note that your problem isn't to do with matchers but how Mockito handles spied varargs methods).
I don't think there were too many huge changes between 1.8.0 and 1.9.5, it shouldn't be too painful.

Invoking a private method via JMockit to test result

Am using JMockit 1.1 and all I want to do is invoke a private method and test the return value. However, I am having trouble understanding exactly how to do this from the JMockit De-Encapsulation example.
The method I am trying to test is the private method in this class:
public class StringToTransaction {
private List<String> parseTransactionString(final String input) {
// .. processing
return resultList;
}
}
And my test code is below.
#Test
public void testParsingForCommas() {
final StringToTransaction tested = new StringToTransaction();
final List<String> expected = new ArrayList<String>();
// Add expected strings list here..
new Expectations() {
{
invoke(tested, "parseTransactionString", "blah blah");
returns(expected);
}
};
}
And the error I am getting is:
java.lang.IllegalStateException: Missing invocation to mocked type at
this point; please make sure such invocations appear only after the
declaration of a suitable mock field or parameter
Perhaps I have misunderstood the whole API here, because I don't think I want to mock the class.. just test the result of calling the private method.
I think you are making this too complicated. You should not be using the Expectations block at all. All you need to do is something like this:
#Test
public void testParsingForCommas() {
StringToTransaction tested = new StringToTransaction();
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah");
assertEquals(expected, actual);
}
Basically, call a private method via Deencapsulation and test that the actual is equal to the expected. Just like you would if the method were public. No mocking is being done, so no Expectations block is needed.
At this point, I don't know if JMockit can or should be used for this. Testing my private method can be done with plain old reflection, although I started this exercise to learn about JMockit (and test my code). In case JMockit cannot be used for this, here is how I can use reflection instead.
#Test
public void testParsingForCommas() throws Exception {
StringToTransaction tested = new StringToTransaction();
ArrayList<String> expected = new ArrayList<>();
expected.add("Test");
Method declaredMethod =
tested.getClass().getDeclaredMethod("parseTransactionString",
String.class);
declaredMethod.setAccessible(true);
Object actual = declaredMethod.invoke(tested, "blah blah");
assertEquals(expected, actual);
}
The call to setAccessible(true) is important here or the invoke will blow up when calling a private method.
declaredMethod.setAccessible(true);
But you want to know what is really cool? If you don't call setAccessible(true), it will blow up with a java.lang.StackOverflowError! :)
As mocking private methods is not allowed in latest Jmockit. One can mock the APIs used inside that private method as a Workaround instead of mocking the private method.
This workaround can also be treated as a final solution.
Example:
Actual Class:
class A {
private int getId(String name){ //private method
return DAOManager.getDao().getId(name); //Call to non-private method can be mocked.
}
}
Test Class:
public class ATest{
#Before
public void setUp(){
new MockDAOManager();
}
//Mock APIs used by the private method `getId`.
public static class MockDAOManager extends MockUp<MockDAOManager>{
static mocked_user_id = 101;
#Mock
public DAOManager getDao() throws Exception{
return new DAOManager();
}
#Mock
public Integer getId(String name){
return mocked_user_id;
}
}
}
Note:
If you don't have such logic(private method calls to another non-private
method) then you may have to refactor your code, Otherwise this will
not work.
Here DAOManager.getDao().getId(name) is not a private API.
There may be a need to mock all APIs used by that private method.
start from 1.35(?) jmockit removed that helper method. for reasons that it is no longer useful (which I don't quite understand)
but yes, this utility is available somewhere else
org.springframework.test.util.ReflectionTestUtils
As mentioned by #Jeff Olson, you can also call the private methods of a bean by declaring them #Tested.
Here is an example:
// Java
#Tested
private YourServiceImplClass serviceImpl;
#Test
public void testPrivateMethod() {
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(serviceImpl, "yourPrivateMethod", "arguments");
assertEquals(expected, actual);
}
Why do you want to test the private method directly ? Most of the times API methods i.e. public interface methods are unit tested as private methods will be be indirectly tested as well along with them. You can put assert statements with expected values from private methods where you call them within the public methods. So if assert fails you are sure that there is some issue with the private method. So you need not test it separately.

Categories

Resources