0
@Test
fun isEmpty_null_true(){
    Assert.assertEquals(StringUtils.isEmpty(null),true)
}

public static boolean isEmpty(@Nullable String value) {
    return (TextUtils.isEmpty(value) || value.trim().isEmpty());
}

All test methods except above one are working and passed. I am getting java.lang.NullPointerException for this one. The implementation of StringUtils.isEmpty() is also mentioned above. StringUtils class is written in Java whereas test case file is written in Kotlin.

Harish Gyanani
  • 1,366
  • 2
  • 22
  • 43

4 Answers4

4

The problem lies in this StringUtils.isEmpty() method itself because sometime TextUtils.isEmpty(null) returns false at that time you are passing value as null then you are invoking trim() method on the null value that is causing the java.lang.NullPointerException modify the method like this to avoid java.lang.NullPointerException

public static boolean isEmpty(@Nullable String value) {
        return (TextUtils.isEmpty(value) || (value != null && value.trim().isEmpty()));
    }
Arpan Sarkar
  • 2,301
  • 2
  • 13
  • 24
  • I got your point but just to make unit test pass, I cannot change method implementation. I have seen link attached. Can you provide a way to really call TextUtils method or mock completely only for these methods. Not for all. – Harish Gyanani Jul 16 '20 at 05:46
  • @HarishGyanani: "I cannot change method implementation" -- you do not have a choice. Your method claims to support `null` as a value, and it does not. You could change `@Nullable` to `@NotNull` and remove the unit test, or you could rewrite the method to be `null`-safe, as in this answer. – CommonsWare Jul 17 '20 at 10:58
  • Change in `Nullable` to `NotNull` is also a change in code so the tests should be according to the current code as OP is only doing the testing part. – Pavneet_Singh Jul 20 '20 at 13:41
1

As you know, || operator will invoke the code on both sides (to get one true value) and null.trim().. will cause the exception.

Since the expected behavior of StringUtils.isEmpty method is to throw an exception when a null value is being passed so you should write the unit test to expect an exception with null value as:

@Test(expected = NullPointerException::class)
fun isEmpty_null_exception(){
    StringUtils.isEmpty(null)
}

here excepted is used to assert that this test method throws a NullPointerException exception.

Note: Using mock for StringUtils.isEmpty static method is done with PowerMock framework but this will violate the purpose of testing to test the actual behavior of code so use the above-recommended approach to verify exception. You may want to create a mocked input variable and mock trim method but then you can simply use a non-null input string, won't be any difference.

Pavneet_Singh
  • 36,884
  • 5
  • 53
  • 68
0

The complete solution, I have got-
Due to default values set in app/build.gradle, I was getting false returned from TextUtils.isEmpty() which was not expected by me.

testOptions {
    unitTests.returnDefaultValues = true
}

Reference - TextUtils.isEmpty(null) returns false
I cannot change the value in build.gradle file, so I needed the solution for my unit test method only. There is a way to provide implementation to TextUtils.isEmpty() method and get the real returned value.

    @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);
            }
        });
   }

Reference - Need help to write a unit test using Mockito and JUnit4

I got the same problem with android.graphics.Color.parseColor() so above solution applies to all classes lies in android package.

Harish Gyanani
  • 1,366
  • 2
  • 22
  • 43
  • As mentioned in [my answer](https://stackoverflow.com/a/62936560/4936904), you used the power mock approach as a solution which is clearly a bad practice as the real app will crash with null values yet the bounty is allocated to answer that suggests a code change, can you please justly this? – Pavneet_Singh Jul 20 '20 at 13:46
  • @Pavneet_Singh - Bounty is given to that answer because it has a link of why TextUtils.isEmpty(null) returns false (due to gradle default values param). It was my real project problem and that answer helped me in finding solution. It didn't have proper explanation so I wrote my answer too. – Harish Gyanani Jul 22 '20 at 11:17
  • Have you tried running tests without `unitTests.returnDefaultValues` and with power mock implementation?, your mocked testutil,isempty should return false with powermock but `value.trim()` should throw an exception. if your test is passing, you have successfully implemented a useless test. – Pavneet_Singh Jul 23 '20 at 13:11
-1

Maybe instead of: value.trim().isEmpty()
try this: value.trim().equals("")

LoukasPap
  • 1,244
  • 1
  • 8
  • 17