Mockito dateformat返回不正确的月份; assertEquals失败

时间:2018-08-01 18:40:35

标签: java exception junit mockito simpledateformat

我正在尝试使用Mockito模拟DateFormat。我只希望显示当前月份。在Junit测试中,我正在Junit测试中执行以下操作:

@Before
public void setUp() throws Exception {

    reportQueryParams = ReportQueryParams.builder()
        .id("07")
        .build();
}

@Test
public void tabSerializerTest() {
    DateFormat formatter = Mockito.mock(SimpleDateFormat.class);
    StringBuffer stringBuffer = new StringBuffer("July");
    Mockito.when(formatter.format(Mockito.any(Date.class), Mockito.any(StringBuffer.class),
        Mockito.any(FieldPosition.class))).thenReturn(stringBuffer);

    MetricsSerializer metricsSerializer = new MetricsSerializer();
    String tabSeparated = metricsSerializer.serializeMetrics(reportQueryParams);
    String expected = new StringBuilder().append("074")
        .append("\t")
        .append("July")
        .toString();
    assertEquals(expected, tabSeparated);
}

我正在测试的功能:

public String serializeMetrics(final ReportQueryParams reportQueryParams) {
    stringJoiner = new StringJoiner("\t");
    addValueFromString(reportQueryParams.getId());
    addValueFromString(getCurrentMonth());
    return stringJoiner.toString();
}

private String getCurrentMonth() {
    DateFormat monthFormat = new SimpleDateFormat("MMMMM");
    return monthFormat.format(new Date());
}


private void addValueFromString(final String value) {
    stringJoiner.add(value);
}

我的ReportQueryParams类:

  public class ReportQueryParams {
        private String id;
    }

该函数返回的月份是“八月”。因此,assertEquals失败。我该如何解决?

1 个答案:

答案 0 :(得分:0)

这里的问题是,模拟在任何时候都不会终止于被测类中,因此不会调用已安排的行为。

那是因为您正在使用被测方法创建格式化程序

DateFormat monthFormat = new SimpleDateFormat("MMMMM");

将类与依赖关系紧密耦合,这使得测试很困难,但并非不可能。

不幸的是,PowerMockito允许这样的事情

SimpleDateFormat formatter = mock(SimpleDateFormat.class); 
when(formatter.format(any(Date.class)).thenReturn("July");
PowerMockito.whenNew(SimpleDateFormat.class).withArguments(anyString()).thenReturn(formatter);

//...Do not forget to include @PrepareForTest(SimpleDateFormat.class) on the test class

理想情况下,您应该做的是重构该类以通过构造或方法参数公开任何显式依赖关系,这些依赖关系可以注入被测对象。

public interface MonthProvider {
    private String getCurrentMonth();
}

public class DefaultMonthProvider implements MonthProvider {
    DateFormat monthFormat = new SimpleDateFormat("MMMMM");

    public String getCurrentMonth() {            
        return monthFormat.format(new Date());
    }
}

public class MetricsSerializer {

    MonthProvider provider;
    public MetricsSerializer(MonthProvider provider) {
        this.provider = provider;
    }

    public String serializeMetrics(final ReportQueryParams reportQueryParams) {
        stringJoiner = new StringJoiner("\t");
        addValueFromString(reportQueryParams.getId());
        addValueFromString(provider.getCurrentMonth());
        return stringJoiner.toString();
    }

    private void addValueFromString(final String value) {
        stringJoiner.add(value);
    }
}

可以注入被测对象。

@Before
public void setUp() throws Exception {

    reportQueryParams = ReportQueryParams.builder()
        .id("07")
        .build();
}

@Test
public void tabSerializerTest() {
    //Arrange
    MonthProvider privider = Mockito.mock(MonthProvider.class);
    Mockito.when(provider.getCurrentMonth()).thenReturn("July");    
    MetricsSerializer metricsSerializer = new MetricsSerializer(provider);
    String expected = new StringBuilder().append("07")
        .append("\t")
        .append("July")
        .toString();

    //Act
    String actual = metricsSerializer.serializeMetrics(reportQueryParams);

    //Assert        
    assertEquals(expected, actual);
}