Java Mockito日期格式返回的月份不正确;assertEquals失败

Java Mockito日期格式返回的月份不正确;assertEquals失败,java,exception,junit,mockito,simpledateformat,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() { Da

我正在尝试使用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正在失败。如何解决这个问题?

这里的问题是,在任何时候,模拟都不会在被测试的类中结束,因此不会调用安排的行为

这是因为您正在使用测试中的方法创建格式化程序

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);
}
可以注射到受试者体内

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

更改参数匹配器,还需要在手动创建实例时重构代码以注入类?您能提供一个例子吗?您需要提供更多关于正在测试的内容的详细信息,以及如何在一个可用于重现问题的环境中测试它。我只是使用“getCurrentMonth()”函数获取当前月份。在测试中,我试图模拟这种行为并提供月份。对不起,您应该首先阅读您打算使用的工具的文档。嘲笑是复杂的事情。你不能通过反复试验来了解这一点。你从一个好的教程开始,然后自上而下地学习
Mockito.when(formatter.format(new Date())
错误时,需要类似于
Mockito.when(formatter.format(any())
(其中any是参数匹配器)有没有一种方法可以不使用PowerMockito就可以做到这一点?@TeeJay没有重构subject类中的格式化程序,以便可以注入模拟。格式化程序应该从类或方法“getCurrentMonth()中删除?@TeeJay
getCurrentMonth
将是从subject类中抽象出来的更好选择,因为
SimpleDataFormat
更像是一个实现concernI尝试过的MetricsSerializer mockMonth=mock(MetricsSerializer.class);when(mockMonth.getCurrentMonth())。然后返回(“七月”);但这也给了八月。