【问题标题】:Mock DateFormat in Junit and set Timezone在 Junit 中模拟 DateFormat 并设置时区
【发布时间】:2020-05-17 04:59:32
【问题描述】:

我的 Extension 函数中使用了 SimpleDateFormat,我将 TimeZone 设置为 GMT+6:00。

我想在我的单元测试中模拟日期格式并将 TimeZone 设置为默认值,但是每次我尝试这样做时都会收到 Nullpointer 异常。

java.lang.NullPointerException
    at java.util.Calendar.setTime(Calendar.java:1770)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:943)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936)
    at java.text.DateFormat.format(DateFormat.java:345)
    at com.s.internettime.MainPresenterTest.startDate_and_endDateTest(MainPresenterTest.java:59)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

如何模拟日期格式并设置区域设置?我在 Stackoverflow 上搜索了其他 DateFormat 问题,但没有解决我的问题。

// Extension function
fun Date.format(dateformat: String): String {
    val sdf = SimpleDateFormat(dateformat, Locale.getDefault())
    sdf.setTimeZone(TimeZone.getTimeZone("GMT+6:00"));
    return format.format(this)
}

    // presenter Test
    public class MainPresenterTest {

        private MainPresenter presenter;

        @InjectMocks
        DateFormat formatter;

        @Before
        public void before() {
            formatter = DateFormat.
          getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
            MockitoAnnotations.initMocks(this);
        }

        @Test
        public void startDate_and_endDateTest() {
            MainListView view = mock(MainListView.class);

            presenter = new MainPresenter();
            presenter.attachView(view);

            // formatter.format throws Null pointer 
            Mockito.when(formatter.format(any(Date.class)))
                .thenReturn(TimeZone.getDefault().getDisplayName());

            presenter.getStatus();

            verify(view).showStatus("2019-10-30", "2020-10-30");
        }
    }


// My Presenter class
class MainPresenter() : BasePresenter<MainListView>() {
    private val mainListView: MainListView? = null

    override fun attachView(mainListView: MainListView) {
        super.attachView(mainListView)
    }

    override fun detachView() {
        super.detachView()
    }

    fun getStatus() {
        // parse date

        val start = Date(2019 - 1900, 10, 30).format("yyyy-dd-MM")
        val end = Date(2020 - 1900, 10, 30).format("yyyy-dd-MM")

        mvpView?.showStatus(start, end)
    }
}

【问题讨论】:

  • 不要使用模拟对象调用实际方法。如果要调用实际方法,请使用@InjectMocks。当您想要存根方法而不是调用实际方法时,请使用 @Mock
  • @komatiraju032 谢谢,我改成 InjectMocks 仍然得到 Nullpointer 异常
  • 顺便考虑扔掉长期过时且臭名昭著的麻烦DateFormatSimpleDateFormat 和朋友,并将ThreeTenABP 添加到您的Android 项目中,以便使用java.time,现代Java日期和时间 API。使用起来感觉好多了。
  • @truthsayer 你能分享错误吗
  • @komatiraju032 我已经更新了我的代码,但我一直收到同样的错误。

标签: android junit mockito


【解决方案1】:

您的代码有两个主要问题。

1- formatter 变量是使用 @Mock 注释定义的,但 MockitoAnnotations.initMocks(this); 不会在 before() 方法中调用。

2- presenter 没有使用模拟的 formatter 变量。所以调用Mockito.when 函数实际上没有任何帮助,即使它是正确的。

解决这些问题后,还会出现更多问题。但是,这些是起点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多