首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Java 8时钟测试类的单元

用Java 8时钟测试类的单元
EN

Stack Overflow用户
提问于 2014-11-21 17:30:58
回答 6查看 72.5K关注 0票数 81

Java8引入了java.time.Clock,它可以作为许多其他java.time对象的参数,允许您向它们注入一个真实的或假的时钟。例如,我知道您可以创建一个Clock.fixed(),然后调用Instant.now(clock),它将返回您提供的固定Instant。这听起来很适合单元测试!

然而,我很难弄清楚如何最好地使用它。我有一门类似于以下课程的课程:

代码语言:javascript
复制
public class MyClass {
    private Clock clock = Clock.systemUTC();

    public void method1() {
        Instant now = Instant.now(clock);
        // Do something with 'now'
    }
}

现在,我想对这段代码进行单元测试。我需要能够将clock设置为生成固定时间,以便能够在不同的时间测试method()。显然,我可以使用反射将clock成员设置为特定的值,但是如果我不必求助于反射,那就太好了。我可以创建一个公共setClock()方法,但这感觉是错误的。我不想向方法中添加Clock参数,因为真正的代码不应该与传递时钟有关。

处理这个问题的最佳方法是什么?这是新代码,所以我可以重新组织类。

编辑:为了澄清,我需要能够构造一个MyClass对象,但是能够让这个对象看到两个不同的时钟值(就好像它是一个正常的系统时钟一样)。因此,我不能将固定时钟传递给构造函数。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-11-21 18:42:24

让我把Jon的答案和注释放到代码中:

测试中的类:

代码语言:javascript
复制
public class Foo {
    private final Clock clock;
    public Foo(Clock clock) {
        this.clock = clock;
    }

    public void someMethod() {
        Instant now = clock.instant();   // this is changed to make test easier
        System.out.println(now);   // Do something with 'now'
    }
}

单元测试:

代码语言:javascript
复制
public class FooTest() {

    private Foo foo;
    private Clock mock;

    @Before
    public void setUp() {
        mock = mock(Clock.class);
        foo = new Foo(mock);
    }

    @Test
    public void ensureDifferentValuesWhenMockIsCalled() {
        Instant first = Instant.now();                  // e.g. 12:00:00
        Instant second = first.plusSeconds(1);          // 12:00:01
        Instant thirdAndAfter = second.plusSeconds(1);  // 12:00:02

        when(mock.instant()).thenReturn(first, second, thirdAndAfter);

        foo.someMethod();   // string of first
        foo.someMethod();   // string of second
        foo.someMethod();   // string of thirdAndAfter 
        foo.someMethod();   // string of thirdAndAfter 
    }
}
票数 62
EN

Stack Overflow用户

发布于 2014-11-21 17:34:08

我不想在方法中添加一个时钟参数,因为真正的代码不应该与传入时钟有关。

不..。但是,您可能希望将其视为构造函数参数。基本上你是说你的课需要一个时钟来工作.所以这是一种依赖。将其视为任何其他依赖项,并将其注入构造函数或通过方法。(我个人赞成构造函数注入,但YMMV。)

一旦你不再把它想成某种东西,你就可以轻松地构造自己,并开始把它看作是“另一种依赖”,那么你就可以使用熟悉的技术了。(无可否认,我假设你对依赖注入很满意。)

票数 64
EN

Stack Overflow用户

发布于 2016-07-14 22:36:58

我在这里的游戏有点晚了,但为了补充其他的答案,建议使用一个时钟-这是绝对可行的,通过使用Mockito的doAnswer,您可以创建一个时钟,您可以动态调整您的测试进度。

假设这个类已被修改为在构造函数中接受一个时钟,并在Instant.now(clock)调用中引用时钟。

代码语言:javascript
复制
public class TimePrinter() {
    private final Clock clock; // init in constructor

    // ...

    public void printTheTime() {
        System.out.println(Instant.now(clock));
    }
}

然后,在您的测试设置中:

代码语言:javascript
复制
private Instant currentTime;
private TimePrinter timePrinter;

public void setup() {
   currentTime = Instant.EPOCH; // or Instant.now() or whatever

   // create a mock clock which returns currentTime
   final Clock clock = mock(Clock.class);
   when(clock.instant()).doAnswer((invocation) -> currentTime);

   timePrinter = new TimePrinter(clock);
}

在稍后的测试中:

代码语言:javascript
复制
@Test
public void myTest() {
    myObjectUnderTest.printTheTime(); // 1970-01-01T00:00:00Z

    // go forward in time a year
    currentTime = currentTime.plus(1, ChronoUnit.YEARS);

    myObjectUnderTest.printTheTime(); // 1971-01-01T00:00:00Z
}

您正在告诉Mockito始终运行一个函数,该函数在调用currentTime ()时返回当前的值。Instant.now(clock)会给clock.instant()打电话。现在你可以快速前进,倒带,通常时间旅行比DeLorean更好.

票数 31
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27067049

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档