gpt4 book ai didi

c# - 使用 TestScheduler 对 Akavache 的缓存行为进行单元测试

转载 作者:太空宇宙 更新时间:2023-11-03 19:54:36 25 4
gpt4 key购买 nike

所以我正在尝试在使用 Akavache 的应用程序中测试缓存行为。我的测试看起来像这样:

using Akavache;
using Microsoft.Reactive.Testing;
using Moq;
using NUnit.Framework;
using ReactiveUI.Testing;
using System;
using System.Threading.Tasks;

[TestFixture]
public class CacheFixture
{
[Test]
public async Task CachingTest()
{
var scheduler = new TestScheduler();
// replacing the TestScheduler with the scheduler below works
// var scheduler = CurrentThreadScheduler.Instance;
var cache = new InMemoryBlobCache(scheduler);

var someApi = new Mock<ISomeApi>();
someApi.Setup(s => s.GetSomeStrings())
.Returns(Task.FromResult("helloworld")).Verifiable();
var apiWrapper = new SomeApiWrapper(someApi.Object, cache,
TimeSpan.FromSeconds(10));

var string1 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string1);

scheduler.AdvanceToMs(5000);
// without the TestScheduler, I'd have to 'wait' here
// await Task.Delay(5000);

var string2 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string2);
}
}

SomeApiWrapper使用一个内部 api(用 new Mock<ISomeApi>() 模拟)——为了简单起见——只返回一个字符串。现在的问题是第二个字符串永远不会返回。 SomeApiWrapper处理缓存的类如下所示:

using Akavache;
using System;
using System.Reactive.Linq;
using System.Threading.Tasks;

public class SomeApiWrapper
{
private IBlobCache Cache;
private ISomeApi Api;
private TimeSpan Timeout;

public SomeApiWrapper(ISomeApi api, IBlobCache cache, TimeSpan cacheTimeout)
{
Cache = cache;
Api = api;
Timeout = cacheTimeout;
}

public async Task<string> GetSomeStrings()
{
var key = "somestrings";
var cachedStrings = Cache.GetOrFetchObject(key, DoGetStrings,
Cache.Scheduler.Now.Add(Timeout));

// this is the last step, after this it just keeps running
// but never returns - but only for the 2nd call
return await cachedStrings.FirstOrDefaultAsync();
}

private async Task<string> DoGetStrings()
{
return await Api.GetSomeStrings();
}
}

调试只会引导我到 return await cachedStrings.FirstOrDefaultAsync(); 行- 在那之后它永远不会结束。

当我替换 TestScheduler 时与标准 ( CurrentThreadScheduler.Instance ) 和 scheduler.AdvanceToMs(5000)await Task.Delay(5000) ,一切都按预期工作,但我不希望单元测试运行多秒。

类似的测试,其中 TestScheduler提前超过缓存超时也成功。正是这种情况,缓存条目不应在两个方法调用之间过期。

我在使用 TestScheduler 的方式上有什么地方做错了吗? ?

最佳答案

TaskIObservable 范式之间来回切换时,这是一个相当普遍的问题。在继续进行测试之前尝试等待会进一步加剧这种情况。

关键问题是你在这里阻塞*

return await cachedStrings.FirstOrDefaultAsync();

我说阻塞的意思是代码无法继续处理,直到该语句产生为止。

第一次运行时缓存找不到键,所以它执行你的DoGetStrings。该问题在第二次运行时出现,此时缓存已填充。这次(我猜)已安排好缓存数据的获取。您需要调用请求、观察序列,然后启动调度程序。

更正后的代码在这里(但需要一些 API 更改)

[TestFixture]
public class CacheFixture
{
[Test]
public async Task CachingTest()
{
var testScheduler = new TestScheduler();
var cache = new InMemoryBlobCache(testScheduler);
var cacheTimeout = TimeSpan.FromSeconds(10);

var someApi = new Mock<ISomeApi>();
someApi.Setup(s => s.GetSomeStrings())
.Returns(Task.FromResult("helloworld")).Verifiable();

var apiWrapper = new SomeApiWrapper(someApi.Object, cache, cacheTimeout);

var string1 = await apiWrapper.GetSomeStrings();
someApi.Verify(s => s.GetSomeStrings(), Times.Once());
StringAssert.AreEqualIgnoringCase("helloworld", string1);

testScheduler.AdvanceToMs(5000);

var observer = testScheduler.CreateObserver<string>();
apiWrapper.GetSomeStrings().Subscribe(observer);
testScheduler.AdvanceByMs(cacheTimeout.TotalMilliseconds);

someApi.Verify(s => s.GetSomeStrings(), Times.Once());


StringAssert.AreEqualIgnoringCase("helloworld", observer.Messages[0].Value.Value);
}
}

public interface ISomeApi
{
Task<string> GetSomeStrings();
}

public class SomeApiWrapper
{
private IBlobCache Cache;
private ISomeApi Api;
private TimeSpan Timeout;

public SomeApiWrapper(ISomeApi api, IBlobCache cache, TimeSpan cacheTimeout)
{
Cache = cache;
Api = api;
Timeout = cacheTimeout;
}

public IObservable<string> GetSomeStrings()
{
var key = "somestrings";
var cachedStrings = Cache.GetOrFetchObject(key, DoGetStrings,
Cache.Scheduler.Now.Add(Timeout));

//Return an observerable here instead of "blocking" with a task. -LC
return cachedStrings.Take(1);
}

private async Task<string> DoGetStrings()
{
return await Api.GetSomeStrings();
}
}

这段代码是绿色的,运行时间在亚秒级。

关于c# - 使用 TestScheduler 对 Akavache 的缓存行为进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35275453/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com