建设工程施工合同网站,智能建造专业就业前景,国家备案网,wordpress 论坛插件你可能会用到的 Mock 小技巧Intro最近看到阿迪分享了两篇 Mock 相关的文章#xff0c;于是想把自己遇到的一些可能对你有帮助的一些小技巧分享一下#xff0c;大概总结了一下#xff0c;且看下文AsyncEnumerable在 C# 8 中引入了异步流#xff0c;AsyncEnumerable#xff… 你可能会用到的 Mock 小技巧Intro最近看到阿迪分享了两篇 Mock 相关的文章于是想把自己遇到的一些可能对你有帮助的一些小技巧分享一下大概总结了一下且看下文AsyncEnumerable在 C# 8 中引入了异步流AsyncEnumerable在有些类库中已经引入了这一语法在 StackExchange.Redis 中 HashScanAsync 的返回值就是 IAsyncEnumerableHashEntry使用示例如下var dic new Dictionarystring, string();
await foreach (var entry in db.HashScanAsync(setName, *))
{dic[entry.Name] entry.Value;
}
在 Mock 的时候我们可以通过下面的 MockAsyncEnumerable 比较方便的指定一个 IEnumerable 对象来实现一个 IAsyncEnumerable 对象private class MockAsyncEnumerableT : IAsyncEnumerableT
{private readonly IEnumerableT _data;public MockAsyncEnumerable(IEnumerableT data){_data data;}public IAsyncEnumeratorT GetAsyncEnumerator(CancellationToken cancellationToken new CancellationToken()){return new MockAsyncEnumeratorT(_data.GetEnumerator());}
}private class MockAsyncEnumeratorT : IAsyncEnumeratorT
{private readonly IEnumeratorT _enumerator;public MockAsyncEnumerator(IEnumeratorT enumerator){_enumerator enumerator;}public ValueTask DisposeAsync(){_enumerator.Dispose();return default;}public ValueTaskbool MoveNextAsync(){return new ValueTaskbool(_enumerator.MoveNext());}public T Current _enumerator.Current;
}
使用示例如下var entries new HashEntry[10];
databaseMock.Setup(c c.HashScanAsync(setName, *, 200, 0, 0, CommandFlags.None)).Returns(new MockAsyncEnumerableHashEntry(entries));
HttpClient Mock一个项目中经常会遇到调用第三方的 API如何比较方便的 Mock 一个 HttpClient 的行为呢我们可以通过自定义一个 HttpHandler 来实现自定义响应信息通常我们需要根据不同的请求信息返回不同的响应我们自定义了一个 MockHttpHandler 来实现比较方便的 Mock 第三方 API 的行为实现如下internal class MockHttpHandler : DelegatingHandler
{private readonly FuncHttpRequestMessage, HttpResponseMessage _getResponseFunc;public MockHttpHandler(FuncHttpRequestMessage, HttpResponseMessage getResponseFunc){_getResponseFunc getResponseFunc;}protected override TaskHttpResponseMessage SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){return Task.FromResult(_getResponseFunc(request));}
}
使用示例如下using var client new HttpClient(new MockHttpHandler(req new HttpResponseMessage(HttpStatusCode.BadRequest))){BaseAddress new Uri(https://api.weihanli.xyz/)};
//
using var httpClient new HttpClient(new MockHttpHandler(request
{var statusCode request.RequestUri.AbsoluteUri.Contains(templateId1) ? HttpStatusCode.NotFound : (request.RequestUri.AbsoluteUri.Contains(templateId2) ? HttpStatusCode.BadRequest : HttpStatusCode.InternalServerError);return new HttpResponseMessage(statusCode){Content new StringContent(JsonConvert.SerializeObject(new{Code statusCode.ToString(),Msg The template not exists}))};
}))
MVC HttpContext MockHttpContext mock 示例var services new ServiceCollection().AddScopedCurrentUser(sp new CurrentUser(){UserID 1,UserName admin}).BuildServiceProvider();var mock new MockHttpContext();
// Mock HttpContext.User
mock.SetupGet(x x.User).Returns(new ClaimsPrincipal(new ClaimsIdentity(new Claim[]{new Claim(ClaimTypes.Name, admin),new Claim(ClaimTypes.Email, weihan.liiherb.com),}, JwtBearerDefaults.AuthenticationScheme)));
// Mock RequestServices
mock.Setup(x x.RequestServices).Returns(services);var controller new CommonController(NullLoggerCommonController.Instance)
{ControllerContext new ControllerContext() {HttpContext mock.Object }
};
MVC ExceptionFilter test有时我们会在项目里使用到 ExceptionFilter 来捕获 MVC 中未捕获的异常如果想要针对自定义的 ExceptionFilter 写一些测试用例可以参考下面的测试用例[Fact]
public async Task ExceptionTest()
{var filters new IFilterMetadata[]{new ResultExceptionFilter()};var exceptionContext new ExceptionContext(new ActionContext(){HttpContext new DefaultHttpContext(){RequestServices new ServiceCollection().AddLogging().BuildServiceProvider()},RouteData new RouteData(new RouteValueDictionary(){{controller, Test},{action, Test},}),ActionDescriptor new ActionDescriptor(),}, filters){Exception new NotImplementedException()};var invoker new MockIActionInvoker();invoker.Setup(x x.InvokeAsync()).Callback(() {new ResultExceptionFilter().OnException(exceptionContext);}).Returns(Task.CompletedTask);await invoker.Object.InvokeAsync();// ...
}
Mock Data字符串在我们的代码中经常会出现对输入参数进行校验是否为空对于这样的数据每次都取写一遍就会有点烦所以写了一个自定义测试数据就是返回 null/空字符串实现代码如下public class NullOrEmptyStringDataAttribute : DataAttribute
{public bool IncludeWhitespace { get; set; }public override IEnumerableobject[] GetData(MethodInfo testMethod){yield return new object[] { null };yield return new object[] { string.Empty };if (IncludeWhitespace){yield return new object[] { };}}
}
使用示例如下[Theory]
[NullOrEmptyStringData]
public void Test(string name)
{Assert.True(string.IsNullOrEmpty(name));
}[Theory]
[NullOrEmptyStringData(IncludeWhitespacetrue)]
public void Test1(string name)
{Assert.True(string.IsNullOrWhitespace(name));
}
Number对于 id 之类的数据通过我们需要检查是否大于0在写测试的时候需要考虑小于等于 0 的情况通常我们也可以像上面那样做一个简单的封装实现代码如下public class LessThanOrEqualDataAttribute : DataAttribute
{public int Value { get; set; }public override IEnumerableobject[] GetData(MethodInfo testMethod){yield return new object[] { Value };yield return new object[] { Value - 1 };}
}
使用实例如下[Theory]
[LessThanOrEqualData]
public async Task GetCategoryIdInfo_BadRequest(int id)
{var result await _controller.GetCategoryIdInfo(id, null);result.AssertCode(ErrorCode.BadRequest);
}
More上面是一些我写测试用例的时候可能会用到的一些帮助类或 Mock 方法希望能对你有所帮助~你在写测试用例的过程中还有哪些觉得比较实用或者有哪些测试用例觉得比较难写呢