【问题标题】:Mocking DateFormat, SimpleDateFormat, Date class模拟 DateFormat、SimpleDateFormat、Date 类
【发布时间】:2019-04-30 12:51:25
【问题描述】:

我需要模拟所需的类并获得所需的日期结果。

我已经尝试在 DateFormat 类中模拟 format() 函数,但没有成功。

class XYZ {

   private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
   private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

   public void buildStr(StringBuilder str){
     DATE_FORMAT.setTimeZone(UTC);
     Date date = getDate();
     str.append(DATE_FORMAT.format(date));
   }

   private Date getDate(){
     return new Date();
   }

}

在这段代码中,我希望星号附加“20190430000000”(正是这个值) 但我得到的是当前的 UTC 时间。

【问题讨论】:

  • 不,您不需要模拟 DateFormat、SimpleDateFormat 或 Date。你甚至不应该使用 SimpleDateFormat。你应该有一个Clock,你可以通过Clock.fixed(...)轻松模拟/创建虚拟实例。
  • 您是想用标题中指示的模拟编写测试,还是只想创建一个具有固定日期的Date 实例?
  • 我见过类似的堆栈溢出问题,但无法在我的场景中复制它们。
  • @AnkitGupta 你用的是什么java版本?
  • 您的示例显示完全零模拟,显然您不能模拟任何东西。它还没有显示任何可以实现目标的代码。另一件事:那不是单元测试。我认为您需要从头开始......也许可以尝试编译并运行一个 hello-world 应用程序并遵循有关编程的教程。

标签: java unit-testing junit mockito powermockito


【解决方案1】:

java.time

您正在使用糟糕的日期时间类,这些类在几年前被 JSR 310 中定义的现代 java.time 类所取代。

Clock

java.time 类采用可选的Clock 参数。传递具有测试所需行为的 Clock 对象。 Clock 类具有提供多种特殊行为的静态方法。其中包括固定时刻、在真实时钟前后设置一定时间的滚动时刻,以及改变节奏,例如按整分钟递增。

这已经在 Stack Overflow 上讨论过很多次了。搜索以了解更多信息。

LocalDate ld = LocalDate.of( 2019 , Month.APRIL , 30 ) ;
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
Instant instant = zdt.toInstant() ;
Clock clock = Clock.fixed( instant , z ) ;

现在在您的测试中注入 clock 对象。

ZonedDateTime zdt = ZonedDateTime.now( clock ) ;

如果您想要一个真正的时钟,请使用:

Clock clock = Clock.system( z ) ;

【讨论】:

    【解决方案2】:

    您可以使用固定日期

    LocalDate date = LocalDate.parse("20190430000000", DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    

    此代码示例适用于 java8 或更高版本。

    EDIT1:

    假设:您想编写一个使用固定日期的测试,但在生产中使用当前日期。您可以使用 JUnit、某种依赖注入和 Mockito。

    这是一个抽象的例子,不能直接编译。

    class XYZ {
        @Inject
        private DateProvider dateProvider;
    
        public void buildStr(StringBuilder str){
            LocalDate date = dateProvider.getDate();
    
            // do something with date
        }
    }
    
    class DateProvider {
        public Date getDate() {
            return new Date();
        }
    }
    
    class XYZTest {
        @Mock
        private DateProvider dateProvider;
    
        @InjectMocks
        private XYZ xyz;
    
        @Test
        public void test() {
            LocalDate fixedDate = LocalDate.parse("20190430000000", DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            when(dateProvider.getDate()).thenReturn(fixedDate);
    
            StringBuilder builder = new StringBuilder();
            xyz.buildStr(builder);
    
            // verify builder contains what you expect
        }
    }
    

    在您的服务类中,您定义了一个提供日期的附加组件(此处为DateProvider)。在测试中,您可以通过 Mocktio 提供的注释 @InjectMocks 获得服务的可测试实例。它会将带有@Mock 注释的任何字段作为模拟注入到您的可测试实例中。在您的测试中,您通过when().thenReturn() 定义模拟应该做什么。您的生产代码将使用DateProvider 的实际实现,您将获得当前日期。

    【讨论】:

    • 我不希望为实际服务确定日期。只是在编写测​​试用例时,我需要设置这个特定值
    • @AnkitGupta 你的问题从来没有真正提到或展示过测试,所以我根据假设更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多