【问题标题】:Test failing using Moq and Timer使用 Moq 和 Timer 测试失败
【发布时间】:2016-07-21 17:47:28
【问题描述】:

我有以下测试用例:

private static readonlystring TEST_KEY = "SomeKey";
private static readonly object TEST_VALUE = 2;
private static readonlyTimeSpan TEST_EXPIRATION = TimeSpan.FromSeconds(2);

[TestMethod]
public void SetMethodStoresValueForCorrectTime()
{
    Mock<ObjectCache> mock = new Mock<ObjectCache>();

    // Setup mock's Set method
    mock.Setup(m => m.Set(TEST_KEY, TEST_VALUE, It.IsAny<DateTimeOffset>(), It.IsAny<string>()))
    .Callback(() => mock.Setup(m => m.Get(TEST_KEY, It.IsAny<string>())).Returns(TEST_VALUE));

    MyCache<object> instance = new MyCache<object>(mock.Object);

    // Add value to mocked cache
    instance.Set(TEST_KEY, TEST_VALUE, TEST_EXPIRATION);
    Assert.AreEqual(TEST_VALUE, instance.Get(TEST_KEY));

    // Configure a timer for item's expiration (Make mock's Get method return null)
    Timer timer = new Timer(_ => mock.Setup(m => m.Get(TEST_KEY, It.IsAny<string>())).Returns(null), null, TEST_EXPIRATION.Milliseconds, -1);

    // Wait for TimerCallback to trigger
    Thread.Sleep(TEST_EXPIRATION.Add(TimeSpan.FromSeconds(1)));
    Assert.IsNull(instance.Get(TEST_KEY)); // <-- Failing here

    timer.Dispose();
}

这里是MyCache&lt;T&gt;(它的相关部分):

public class MyCache<TSource> : ICache<TSource>
{
     private ObjectCache _innerCache;

     public MyCache(System.Runtime.Caching.ObjectCache innerCache)
     {
         _innerCache = innerCache;
     }

     // ...

     public TSource Get(string key)
     {
         if (key == null) throw new ArgumentNullException("key");
         object value = _innerCache.Get(key);
         return value != null ? (TSource)value : default(TSource);
     }

     public void Set(string key, TSource value, TimeSpan expiration)
     {
         if (key == null) throw new ArgumentNullException("key");
         _innerCache.Set(key, value, DateTimeOffset.UtcNow.Add(expiration));
     }
}

为什么测试失败了? 最后一个断言失败了:

Assert.IsNull 失败。

我在这里做错了吗?

【问题讨论】:

  • 你为什么要创建一个计时器而不使用它(除了丢弃它)?
  • @JeroenHeier 它应该在TEST_EXPIRATION.Milliseconds毫秒后自动启动

标签: c# multithreading unit-testing moq mstest


【解决方案1】:

我复制了你的代码,测试在我的机器上通过了。

但是您可能应该重新考虑您的测试,因为您正在尝试测试只是包装 ObjectCache 的 MyCache。您不需要测试缓存过期时间(因为这是 ObjectCache 的一部分,并且应该是其单元测试的一部分),只需 MyCache 正确地将 Get 和 Set 操作委托给 ObjectCache。例如:

    [TestMethod]
    public void SetMethodStoresValueInInnerCache()
    {
        Mock<ObjectCache> mock = new Mock<ObjectCache>();

        MyCache<object> instance = new MyCache<object>(mock.Object);

        // Add value to mocked cache
        instance.Set(TEST_KEY, TEST_VALUE, TEST_EXPIRATION);

        mock.Verify(x => x.Set(TEST_KEY, TEST_VALUE, It.IsAny<DateTimeOffset>(), It.IsAny<string>()), Times.Once);
    }

你可以有一个 Get 的等价物。
如果您想测试 MyCache 是否正确设置了过期时间(代码 DateTimeOffset.UtcNow.Add(expiration)),那么您可以在代码中创建类似 ITime 的接口并使用 time.UtcNow(其中 time 是 ITime 的注入实例) - 真正的实现会返回DateTime.UtcNow,在你的单元测试中你可以用一个固定的时间来模拟它(然后断言过期是那个固定的时间加上TEST_EXPIRATION)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多