我可以使用mockito来匹配具有自动更新时间戳的对象吗? [英] Can I use mockito to match an object with an auto updated timestamp?

查看:145
本文介绍了我可以使用mockito来匹配具有自动更新时间戳的对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在进行模拟调用之前自动更新时间戳的最佳方法是什么?

What would be the best way to something like this where a timestamp is updated automatically before making the mocked call?

这是我正在尝试的一些虚拟代码测试:

Here is some dummy code of what I am trying to test:

public class ThingWithATimestamp {
    public Long timestamp;
    public String name;

    public ThingWithATimestamp(String name) {
        this.name = name;
    }
}

public class TheClassThatDoesStuff {
    private ThingConnector connector;

    public TheClassThatDoesStuff(ThingConnector connector) {
        this.connector = connector;
    }

    public void updateTheThing(MyThingWithATimestamp thing) {
        thing.timestamp = currentTimestamp();
        connector.update(thing);            
    }
}

这是我要测试的内容:

public class TheClassThatDoesStuffTests {
    @Test
    public void canUpdateTheThing() {
        ThingConnector connector = mock(ThingConnector.class);
        TheClassThatDoesStuff doer = new ThisClassThatDoesStuff(connector);

        doer.updateTheThing(new ThingWithATimestamp("the name"));

        verify(connector, times(1)).update(SomeMatcherThatICantFigureOut);
    }

我知道这段代码非常愚蠢,但我认为它准确地描绘了我的内容我想验证。我基本上需要一个匹配器来填写测试来验证时间戳是否在当前时间的X之内,所以我知道它已正确更新并且调用了 connector.update 对象的正确时间戳。

I know this code is pretty dumbed down but I think it accurately portrays what I am trying to verify. I basically need a matcher to fill in the test to verify that the timestamp is within X of the current time so I know it got updated correctly and that connector.update was called with the proper timestamp for the object.

推荐答案

我发现处理时间关键代码最强大的方法就是结束所有在他们自己的班级中你的时间关键功能。我通常称它为 TimeHelper 。所以这个类可能如下所示。

I find the most robust way to deal with time-critical code is to wrap up all of your time-critical functions in their own class. I usually call it TimeHelper. So this class might look like the following.

import java.util.Date;
public class TimeHelper{
    public long currentTimeMillis(){
        return System.currentTimeMillis();
    }
    public Date makeDate(){
        return new Date();
    }
}

它可能有更多相同类型的方法。现在,任何使用这些函数的类都应该有(至少)两个构造函数 - 你将在应用程序中使用的正常构造函数,以及一个包含私有的构造函数,其中 TimeHelper 是一个参数。需要存储此 TimeHelper 以供日后使用。

and it might have more methods of the same type. Now, any class that uses such functions should have (at least) two constructors - the normal one that you'll use in your application, plus a package-private one in which a TimeHelper is a parameter. This TimeHelper needs to be stored away for later use.

public class ClassThatDoesStuff {
    private ThingConnector connector;
    private TimeHelper timeHelper;

    public ClassThatDoesStuff(ThingConnector connector) {
        this(connector, new TimeHelper());
    }

    ClassThatDoesStuff(ThingConnector connector, TimeHelper timeHelper) {
        this.connector = connector;
        this.timeHelper = timeHelper;
    } 
}

现在,在你的班级内,而不是写 System.currentTimeMillis(),写 timeHelper.currentTimeMillis()。当然,这将具有完全相同的效果;除了现在,你的班级神奇地变得更加可测试。

Now, within your class, instead of writing System.currentTimeMillis(), write timeHelper.currentTimeMillis(). This will, of course, have exactly the same effect; except now, your class has magically become much more testable.

当你测试你的课程时,模拟 TimeHelper 。配置此模拟(使用Mockito的 thenReturn ,或者 doReturn )返回您喜欢的任何时间值 - 无论您需要什么样的测试。如果你在测试过程中要多次调用 currentTimeMillis(),你甚至可以在这里返回多个值。

When you test your class, make a mock of TimeHelper. Configure this mock (using Mockito's when and thenReturn, or alternatively doReturn) to return any time values you like - whatever you need for your test. You can even return multiple values here, if you're going to have multiple calls to currentTimeMillis() in the course of the test.

现在使用第二个构造函数来创建您要测试的对象,并传入模拟。这使您可以完美控制测试中使用的时间值;并且你可以使你的断言或验证声明确切地使用了正确的值。

Now use the second constructor to make the object that you're going to test, and pass in the mock. This gives you perfect control of what time values will be used in the test; and you can make your assertions or verifications assert that precisely the right value has been used.

public class ClassThatDoesStuffTest{
    @Mock private TimeHelper mockTime;
    @Mock private ThingConnector mockConnector;
    private ClassThatDoesStuff toTest;

    @Test
    public void doesSomething(){
        // Arrange
        initMocks(this);
        when(mockTime.currentTimeMillis()).thenReturn(1000L, 2000L, 5000L);
        toTest = new ClassThatDoesStuff(mockConnector, mockTime);

        // Act
        toTest.doSomething();

        // Assert
        // ... ???
    }
}        

如果你这样做,你知道你的测试会始终工作,永远不会依赖于操作系统的切片策略。您还可以验证时间戳的确切值,而不是断言它们在一定的时间间隔内。

If you do this, you know that your test will always work, and never be dependent on the time slicing policies of your operating system. You also have the power to verify the exact values of your timestamps, rather than asserting that they fall within some approximate interval.

这篇关于我可以使用mockito来匹配具有自动更新时间戳的对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆