Need help to write a unit test using Mockito and JUnit4

前端 未结 10 1035
余生分开走
余生分开走 2020-12-15 04:06

Need help to write a unit test for the below code using Mockito and JUnit4,

public class MyFragmentPresenterImpl { 
      public Boolean isValid(String value         


        
相关标签:
10条回答
  • 2020-12-15 04:29

    This is a known issue, due to a clause in Testing Fundamental of Android which says:

    You can use the JUnit TestCase class to do unit testing on a class that does not call Android APIs.

    The default behavior is problematic when using classes like Log or TextUtils.

    To sum up:

    1. android.jar is mock before, so some Android API return value may not be as expected.
    2. JUnit itself is a single measure for the java code, so try not to use the Android API methods.

    Source: http://www.liangfeizc.com/2016/01/28/unit-test-on-android/

    0 讨论(0)
  • 2020-12-15 04:29

    I replaces everywhere in my project TextUtils.isEmpty(...) with this:

    /**
     * Util class to be used instead of Android classes for Junit tests.
     */
    public class Utils {
    
        /**
         * Returns true if the string is null or 0-length.
         * @param str the string to be examined
         * @return true if str is null or zero length
         */
        public static boolean isEmpty(@Nullable CharSequence str) {
            return str == null || str.length() == 0;
        }
    }
    
    0 讨论(0)
  • 2020-12-15 04:30

    I was able to solve this error by running the test class with the following.

    @RunWith(RobolectricGradleTestRunner.class)
    public class MySimpleTest {
    .....a bunch of test cases
    }
    

    This wiki page explains in greater detail https://github.com/yahoo/squidb/wiki/Unit-testing-with-model-objects

    0 讨论(0)
  • 2020-12-15 04:34

    Because of JUnit TestCase class cannot use Android related APIs, we have to Mock it.
    Use PowerMockito to Mock the static class.

    Add two lines above your test case class,

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(TextUtils.class)
    public class YourTest
    {
    
    }
    

    And the setup code

    @Before
    public void setup() {
        PowerMockito.mockStatic(TextUtils.class);
        PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(new Answer<Boolean>() {
            @Override
            public Boolean answer(InvocationOnMock invocation) throws Throwable {
                CharSequence a = (CharSequence) invocation.getArguments()[0];
                return !(a != null && a.length() > 0);
            }
        });
    }
    

    That implement TextUtils.isEmpty() with our own logic.

    Also, add dependencies in app.gradle files.

    testCompile "org.powermock:powermock-module-junit4:1.6.2"
    testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
    testCompile "org.powermock:powermock-api-mockito:1.6.2"
    testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
    

    Thanks Behelit's and Exception's answer.

    0 讨论(0)
  • 2020-12-15 04:38

    add this line in your gradle file in case of Android Studio.

    android{
    ....
     testOptions {
            unitTests.returnDefaultValues = true
     }
    }
    
    0 讨论(0)
  • 2020-12-15 04:38

    Solution 1:

    I would like to provide a Kotlin and a Java version.

    Kotlin version:

    import android.text.TextUtils
    
    import org.junit.Before
    
    import org.junit.runner.RunWith
    
    import org.mockito.Matchers.any
    
    import org.powermock.api.mockito.PowerMockito
    

    import org.powermock.core.classloader.annotations.PrepareForTest

    import org.powermock.modules.junit4.PowerMockRunner
    
    
    
    @RunWith(PowerMockRunner::class)
    
    @PrepareForTest(TextUtils::class)
    
    class UserOwnedDataTest1 {
    
    
    
        @Before
    
        fun setup() {
    
            PowerMockito.mockStatic(TextUtils::class.java)
    
            PowerMockito.`when`(TextUtils.isEmpty(any(CharSequence::class.java))).thenAnswer { invocation ->
    
                val a = invocation.arguments[0] as? CharSequence
    
               a?.isEmpty() ?: true
    
            }
    
        }
    
    }
    

    Java version:

    import android.text.TextUtils;
    
    
    
    import org.junit.Before;
    
    import org.junit.runner.RunWith;
    
    import org.mockito.stubbing.Answer;
    
    import org.powermock.api.mockito.PowerMockito;
    
    import org.powermock.core.classloader.annotations.PrepareForTest;
    
    import org.powermock.modules.junit4.PowerMockRunner;
    
    
    
    import static org.mockito.Matchers.any;
    
    
    
    @RunWith(PowerMockRunner.class)
    
    @PrepareForTest(TextUtils.class)
    
    public final class UserOwnedDataTest2 {
    
    
    
        @Before
    
        public void setup() {
    
            PowerMockito.mockStatic(TextUtils.class);
    
            PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer((Answer<Boolean>) invocation -> {
    
                CharSequence a = (CharSequence) invocation.getArguments()[0];
    
                return !(a != null && a.length() > 0);
    
            });
    
        }
    
    }
    

    Do not forget to add the dependencies:

    testCompile "org.powermock:powermock-module-junit4:1.6.2"
    
    testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
    
    testCompile "org.powermock:powermock-api-mockito:1.6.2"
    
    testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
    

    I remember that we still need another dependency, but not clearly.

    Anyway you could fix the missing dependency easily.

    Solution 2:

    Or you could add the same package and class name with TextUtils

    package android.text;
    
    
    
    public class TextUtils {
    
        public static boolean isEmpty( CharSequence str) {
    
            return str == null || str.length() == 0;
    
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题