2016-07-21 21 views
0

Ich habe den folgenden Testfall:Test nicht mit Moq und Timer

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

Und hier ist MyCache<T> (der relevante Teil davon):

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

Warum ist der Test nicht bestehen? Es basiert auf der letzten Behauptung Versagen:

Assert.IsNull fehlgeschlagen.

Mache ich hier etwas falsch?

+0

Warum erstellen Sie einen Timer und verwenden ihn nicht (außer es zu entsorgen)? –

+0

@JeroenHeier Es sollte automatisch nach 'TEST_EXPIRATION.Milliseconds' Millisekunden beginnen –

Antwort

0

Ich habe Ihren Code kopiert und der Test läuft auf meinem Rechner.

Sie sollten jedoch wahrscheinlich Ihren Test überdenken, während Sie versuchen, MyCache zu testen, die einfach ObjectCache umschließt. Sie müssen den Cache-Ablauf nicht testen (da dies Teil von ObjectCache ist und Teil seiner Komponententests sein sollte), aber nur, dass MyCache die Vorgänge Get und Set ordnungsgemäß an ObjectCache delegiert. Zum Beispiel:

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

Sie könnten ein Äquivalent für die Get haben.
Wenn Sie testen möchten, dass myCache das Ablauf richtig einstellen (der Code DateTimeOffset.UtcNow.Add(expiration)), dann könnten Sie eine Schnittstelle wie ITime erstellen und verwenden time.UtcNow in Ihrem Code (wo die Zeit eine injiziert Instanz ITime ist) - die reale Umsetzung würde zurückkehren DateTime.UtcNow und in Ihrem Komponententest konnten Sie es mit einer festen Zeit vortäuschen (und dann behaupten, dass das Ablaufdatum diese feste Zeit plus TEST_EXPIRATION war)