3

The follows was the code which I want to test.

public class Demo {

   private static final List<Pair<String, String>> mList;

   static {
     mList = new ArrayList<>();
     mList.add(new Pair<>("F0", "T1"));
     mList.add(new Pair<>("F1", "T2"));
     mList.add(new Pair<>("F2", "T3"));
   }

   public String getStr(int pos) {
     return mList.get(pos).first;
   }
}

I was an android developer. I have get some trouble in test and mock the code.I have use mockito. I have try some code to test it,but the result was not my expect.

1.First try

@Test
public void test(){
    Demo demo=new Demo();
    assertEquals(demo.getStr(0),"F0");
    /**
    *  java.lang.AssertionError: 
    *  Expected :null 
    *  Actual   :F0
    */
}

2.Second try

@Test
public void test() {
    Demo demo = mock(Demo.class);

    doCallRealMethod().when(demo).getStr(0);
    assertEquals(demo.getStr(0), "F0");
    /**
     *  java.lang.AssertionError: 
     *  Expected :null
     *  Actual   :F0
     */
}

Anyone tell me how can I resolve this problem to make demo.getStr(0) == "F0" by call the real method? Thanks!

===========================

Another question relate to it

I have try an another test to test android.util.Pair class, and the result is that "pair.first" was null,.(There are androidTest and test directory,I put it into test package.Did it impact the result?)

import android.util.Pair;

import org.junit.Test;
import org.mockito.Mockito;

import static org.junit.Assert.assertEquals;

public class DemoTest {
    @Test
    public  void test1(){
        Pair<String,String> pair=new Pair("First","Second");
        assertEquals("First",pair.first);
        //pair.first was null,why?
    }

    @Test
    public void test2(){
        Pair<String,String> pair= Mockito.spy(Pair.class);
        assertEquals("First",pair.first);
        //pair.first was null also,why?
    }
}

Why the simple code is correct in real android environment,but failure in test?

Siavash Abdoli
  • 1,852
  • 3
  • 22
  • 38
chenjj2048
  • 101
  • 2
  • 6
  • why the result is always null? – chenjj2048 Sep 05 '16 at 13:36
  • In the first implementation you are not even using mockito. It seems that the `first` field of the `Pair` class is realy `null`. – Apokralipsa Sep 05 '16 at 14:03
  • @Apokralipsa But in the second implementation it is still null, why? That trouble me for a long time. Can you give me a correct demonstrate for the example?Should I use PowerMock because of the field is static and final? – chenjj2048 Sep 05 '16 at 14:57

4 Answers4

9

I had the same problem too. month ago I have problem with TextUtils class too.

I report this to jUnit but they told me the problem is with android package because in unit test environment you don't have access to platform specific classes

for that pair case you can use this package. this works for me

import android.support.v4.util.Pair;
Siavash Abdoli
  • 1,852
  • 3
  • 22
  • 38
0

The problem in your first try is, that the public field "first" is actually null.

Is the Pair class the one from the "javafx.util" package or a custom implementation? Did you forget "this.first = first" or something similar in the constructor of the "Pair" class?

I would also recommend to change the following line:

assertEquals(demo.getStr(0),"F0");

to

assertEquals("F0", demo.getStr(0));

so that the error is printed correctly.

Your second try does not make any sense. What is the point in mocking the class you want to test?

I think the second example has the same problem as the first one. Pair.first is never set. If you fix that, it should also work (untested).

msmith
  • 43
  • 5
  • The Pair class is android.util.Pair. It has the constructor to set the first and second field. I have change the code to "assertEquals("F0", demo.getStr(0));", but It also return null. – chenjj2048 Sep 06 '16 at 12:40
0

From Google's Android tools website:


"Method ... not mocked."

The android.jar file that is used to run unit tests does not contain any actual code - that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito).


So how can we solve this?

In other words. If you need a default android class to work properly you either have to include it from a separate repository, or implement it yourself.

In the case of Android's Pair class. You can use android.support.v4.util.Pair instead.

To get access to this class, you can include com.android.support:support-compat:27.0.0 in your build.gradle or dependencies file.

If you are not using Gradle, you can copy the implementation of this file and use it in place of the official one. Or you can try and download the .jar file from this older version https://mvnrepository.com/artifact/com.google.android/support-v4/r7 (I have not tested whether it works)

ZeroStatic
  • 364
  • 1
  • 3
  • 13
0

Another approach (based on this) is to create the class in app/src/test/java/android/util/Pair.java and copy the code from the Android implementation.

This way you don't need extra dependencies. (There may be issues related to the implementation changing after you make the copy, but the dependencies may become stale as well.)

ciobi
  • 97
  • 1
  • 10