Pau*_*ner 30 c# unit-testing asp.net-web-api
我正在尝试编写一些单元测试,以确保对我的Web API发出的请求被路由到具有预期参数的预期API控制器操作.
我试图使用HttpServer
该类创建一个测试,但我从服务器得到500个响应,没有信息来调试问题.
有没有办法为ASP.NET Web API站点的路由创建单元测试?
理想情况下,我想创建一个请求HttpClient
,让服务器处理请求并将其传递给预期的路由进程.
Fil*_*p W 26
我写了一篇关于测试路线的博客文章,并且做了很多你要问的事情:
http://www.strathweb.com/2012/08/testing-routes-in-asp-net-web-api/
希望能帮助到你.
另外一个优点是我使用反射来提供动作方法 - 所以不要使用带有字符串的路径,而是以强类型方式添加它们.使用这种方法,如果您的操作名称发生变化,测试将无法编译,因此您可以轻松地发现错误.
测试ASP.NET Web API应用程序路由的最佳方法是对端点进行集成测试.
这是ASP.NET Web API应用程序的简单集成测试示例.这不是主要测试您的路线,但它无形地测试它们.此外,我在这里使用XUnit,Autofac和Moq.
[Fact, NullCurrentPrincipal]
public async Task
Returns_200_And_Role_With_Key() {
// Arrange
Guid key1 = Guid.NewGuid(),
key2 = Guid.NewGuid(),
key3 = Guid.NewGuid(),
key4 = Guid.NewGuid();
var mockMemSrv = ServicesMockHelper
.GetInitialMembershipService();
mockMemSrv.Setup(ms => ms.GetRole(
It.Is<Guid>(k =>
k == key1 || k == key2 ||
k == key3 || k == key4
)
)
).Returns<Guid>(key => new Role {
Key = key, Name = "FooBar"
});
var config = IntegrationTestHelper
.GetInitialIntegrationTestConfig(GetInitialServices(mockMemSrv.Object));
using (var httpServer = new HttpServer(config))
using (var client = httpServer.ToHttpClient()) {
var request = HttpRequestMessageHelper
.ConstructRequest(
httpMethod: HttpMethod.Get,
uri: string.Format(
"https://localhost/{0}/{1}",
"api/roles",
key2.ToString()),
mediaType: "application/json",
username: Constants.ValidAdminUserName,
password: Constants.ValidAdminPassword);
// Act
var response = await client.SendAsync(request);
var role = await response.Content.ReadAsAsync<RoleDto>();
// Assert
Assert.Equal(key2, role.Key);
Assert.Equal("FooBar", role.Name);
}
}
Run Code Online (Sandbox Code Playgroud)
我用这个测试有一些外部助手.其中一个是NullCurrentPrincipalAttribute
.由于您的测试将在您的Windows身份下运行,因此Thread.CurrentPrincipal
将使用此身份进行设置.因此,如果您在应用程序中使用某种授权,最好首先摆脱这种情况:
public class NullCurrentPrincipalAttribute : BeforeAfterTestAttribute {
public override void Before(MethodInfo methodUnderTest) {
Thread.CurrentPrincipal = null;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我创建了一个模拟MembershipService
.这是应用程序特定的设置.因此,这将根据您自己的实现进行更改.
在GetInitialServices
我创建Autofac容器.
private static IContainer GetInitialServices(
IMembershipService memSrv) {
var builder = IntegrationTestHelper
.GetEmptyContainerBuilder();
builder.Register(c => memSrv)
.As<IMembershipService>()
.InstancePerApiRequest();
return builder.Build();
}
Run Code Online (Sandbox Code Playgroud)
该GetInitialIntegrationTestConfig
方法只是初始化我的配置.
internal static class IntegrationTestHelper {
internal static HttpConfiguration GetInitialIntegrationTestConfig() {
var config = new HttpConfiguration();
RouteConfig.RegisterRoutes(config.Routes);
WebAPIConfig.Configure(config);
return config;
}
internal static HttpConfiguration GetInitialIntegrationTestConfig(IContainer container) {
var config = GetInitialIntegrationTestConfig();
AutofacWebAPI.Initialize(config, container);
return config;
}
}
Run Code Online (Sandbox Code Playgroud)
该RouteConfig.RegisterRoutes
方法基本上记录了我的路线.我也有一点点扩展方法来创建一个HttpClient
在HttpServer
.
internal static class HttpServerExtensions {
internal static HttpClient ToHttpClient(
this HttpServer httpServer) {
return new HttpClient(httpServer);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,我有一个静态类HttpRequestMessageHelper
,它有一堆静态方法来构造一个新HttpRequestMessage
实例.
internal static class HttpRequestMessageHelper {
internal static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri) {
return new HttpRequestMessage(httpMethod, uri);
}
internal static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri, string mediaType) {
return ConstructRequest(
httpMethod,
uri,
new MediaTypeWithQualityHeaderValue(mediaType));
}
internal static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri,
IEnumerable<string> mediaTypes) {
return ConstructRequest(
httpMethod,
uri,
mediaTypes.ToMediaTypeWithQualityHeaderValues());
}
internal static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri, string mediaType,
string username, string password) {
return ConstructRequest(
httpMethod, uri, new[] { mediaType }, username, password);
}
internal static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri,
IEnumerable<string> mediaTypes,
string username, string password) {
var request = ConstructRequest(httpMethod, uri, mediaTypes);
request.Headers.Authorization = new AuthenticationHeaderValue(
"Basic",
EncodeToBase64(
string.Format("{0}:{1}", username, password)));
return request;
}
// Private helpers
private static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri,
MediaTypeWithQualityHeaderValue mediaType) {
return ConstructRequest(
httpMethod,
uri,
new[] { mediaType });
}
private static HttpRequestMessage ConstructRequest(
HttpMethod httpMethod, string uri,
IEnumerable<MediaTypeWithQualityHeaderValue> mediaTypes) {
var request = ConstructRequest(httpMethod, uri);
request.Headers.Accept.AddTo(mediaTypes);
return request;
}
private static string EncodeToBase64(string value) {
byte[] toEncodeAsBytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(toEncodeAsBytes);
}
}
Run Code Online (Sandbox Code Playgroud)
我在我的应用程序中使用基本身份验证.因此,这个类有一些HttpRequestMessege
使用Authentication头构造一个的方法.
最后,我做了我的Act和Assert来验证我需要的东西.这可能是一个矫枉过正的样本,但我认为这会给你一个好主意.
这是一篇关于使用HttpServer进行集成测试的精彩博客文章.另外,这是另一篇关于ASP.NET Web API中测试路由的精彩文章.
归档时间: |
|
查看次数: |
20842 次 |
最近记录: |