简体   繁体   中英

How to unit testing a class that uses android.icu.text.* library with JUnit and Mockito in Android Studio? (in Java)

I am writing a class which handles formatting input text with given pattern. I am using android.icu.text.DecimalFormat and android.icu.text.DecimalFormatSymbols (I used the java.text.Decimalformat before but it did not worked correctly on the real android device so I switch to use android.icu.text.* classes) I am facing some issues:

At first It throws Method... is not mocked. I fixed this one by add the testOptions in the build.gradle file. But then the DecimalFormat instance always returns null .

I tried every thing and It still does not accept my test case. Please help me. Thank you very much

My class:

import android.icu.text.DecimalFormat;
import android.icu.text.DecimalFormatSymbols;

import androidx.annotation.NonNull;

import java.util.Locale;

public class NumberFormatter {
    public String format(String inputText, String pattern){
        DecimalFormatSymbols decimalFormatSymbol = getDefaultDecimalFormatSymbols();
        DecimalFormat decimalFormat = getDecimalFormat(pattern, decimalFormatSymbol);
        double value = Double.parseDouble(inputText);
        return decimalFormat.format(value);
    }

    @NonNull
    DecimalFormat getDecimalFormat(String pattern, DecimalFormatSymbols decimalFormatSymbol) {
        return new DecimalFormat(pattern, decimalFormatSymbol);
    }

    @NonNull
    DecimalFormatSymbols getDefaultDecimalFormatSymbols() {
        DecimalFormatSymbols decimalFormatSymbol = new DecimalFormatSymbols(Locale.getDefault());
        decimalFormatSymbol.setDecimalSeparator('.');
        decimalFormatSymbol.setGroupingSeparator(',');
        return decimalFormatSymbol;
    }
}

My test class:

import android.icu.text.DecimalFormat;
import android.icu.text.DecimalFormatSymbols;

import org.junit.Assert;
import org.junit.Test;

public class NumberFormatterTest {

    @Test
    public void format_givenInputStringAndPatternString_shouldReturnCorrespondingFormattedString(){
        String pattern = "#,###.##";
        String inputString = "1000.12";
        String expect = "1,000.12";
        String actual = new NumberFormatter().format(inputString, pattern);

        Assert.assertEquals(expect, actual);
    }
}

At first it showed this error

Method setDecimalSeparator in android.icu.text.DecimalFormatSymbols not mocked. See http://g.co/androidstudio/not-mocked for details.
java.lang.RuntimeException: Method setDecimalSeparator in android.icu.text.DecimalFormatSymbols not mocked. See http://g.co/androidstudio/not-mocked for details.

After adding to gradle file like this:

testOptions {
    unitTests.returnDefaultValues = true
}

Then is always return NULL

expected:<1,000.12> but was:<null>
Expected :1,000.12
Actual   :null
<Click to see difference>

java.lang.AssertionError: expected:<1,000.12> but was:<null>
    at org.junit.Assert.fail(Assert.java:89)
    at org.junit.Assert.failNotEquals(Assert.java:835)
    at org.junit.Assert.assertEquals(Assert.java:120)
    at org.junit.Assert.assertEquals(Assert.java:146)

I tried to add testOptions in to build.gradle I tried to mock the DecimalFormat object I expected that it could return some object with my settings but it always return null

When you're using android classes in your unit tests, they are actually mocks , not real objects. The error you're seeing indicates that you're trying to access mocked android framework object, in your instance DecimalFormat.

You can either change android classes to java classes, as JakeB suggested or you can use some framework like Robolectric to make android framework partially work in unit tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM