asp.net 集成测试_简化ASP.NET Core应用程序的功能和集成测试

asp.net 集成测试

asp.net 集成测试

.NET Test Explorer

In ASP.NET 2.1 (now in preview) there's apparently a new package called Microsoft.AspNetCore.Mvc.Testing that's meant to help streamline in-memory end-to-end testing of applications that use the MVC pattern. I've been re-writing my podcast site at https://hanselminutes.com in ASP.NET Core 2.1 lately, and recently added some unit testing and automatic unit testing with code coverage. Here's a couple of basic tests. Note that these call the Razor Pages directly and call their OnGet() methods directly. This shows how ASP.NET Core is nicely factored for Unit Testing but it doesn't do a "real" HTTP GET or perform true end-to-end testing.

在ASP.NET 2.1(现在预览)中,显然有一个名为Microsoft.AspNetCore.Mvc.Testing的新程序包,该程序包旨在帮助简化使用MVC模式的应用程序的内存端到端测试。 最近,我一直在用ASP.NET Core 2.1重写https://hanselminutes.com上的播客站点,最近又添加了一些单元测试和具有代码​​覆盖率的自动单元测试。 这是几个基本测试。 请注意,这些直接调用Razor页面,并直接调用其OnGet()方法。 这说明了如何将ASP.NET Core很好地用于单元测试,但它没有执行“真实的” HTTP GET或执行真正的端到端测试。

These tests are testing if visiting URLs like /620 will automatically redirect to the correct full canonical path as they should.

这些测试用于测试访问的URL(例如/ 620)是否会自动重定向到正确的完整规范路径。

[Fact]
public async void ShowDetailsPageIncompleteTitleUrlTest()
{
// FAKE HTTP GET "/620"
IActionResult result = await pageModel.OnGetAsync(id:620, path:"");

RedirectResult r = Assert.IsType<RedirectResult>(result);
Assert.NotNull(r);
Assert.True(r.Permanent); //HTTP 301?
Assert.Equal("/620/jessica-rose-and-the-worst-advice-ever",r.Url);
}

[Fact]
public async void SuperOldShowTest()
{
// FAKE HTTP GET "/default.aspx?showId=18602"
IActionResult result = await pageModel.OnGetOldShowId(18602);

RedirectResult r = Assert.IsType<RedirectResult>(result);
Assert.NotNull(r);
Assert.True(r.Permanent); //HTTP 301?
Assert.StartsWith("/615/developing-on-not-for-a-nokia-feature",r.Url);
}

I wanted to see how quickly and easily I could do these same two tests, except "from the outside" with an HTTP GET, thereby testing more of the stack.

我想看看我能多么快速,轻松地完成这两个测试,除了使用HTTP GET从外部进行测试之外,从而测试了更多堆栈。

I added a reference to Microsoft.AspNetCore.Mvc.Testing in my testing assembly using the command-line equivalanet of "Right Click | Add NuGet Package" in Visual Studio. This CLI command does the same thing as the UI and adds the package to the csproj file.

我在测试程序集中使用Visual Studio中“右键单击|添加NuGet程序包”的命令行等效项添加了对Microsoft.AspNetCore.Mvc.Testing的引用。 此CLI命令执行与UI相同的操作,并将程序包添加到csproj文件中。

dotnet add package Microsoft.AspNetCore.Mvc.Testing -v 2.1.0-preview1-final

It includes a new WebApplicationTestFixture that I point to my app's Startup class. Note that I can take store the HttpClient the TestFixture makes for me.

它包含一个新的WebApplicationTestFixture,我指向应用程序的Startup类。 请注意,我可以存储TestFixture为我制作的HttpClient。

public class TestingMvcFunctionalTests : IClassFixture<WebApplicationTestFixture<Startup>>
{
public HttpClient Client { get; }

public TestingMvcFunctionalTests(WebApplicationTestFixture<Startup> fixture)
{
Client = fixture.Client;
}
}

No tests yet, just setup. I'm using SSL redirection so I'll make sure the client knows that, and add a test:

尚无测试,只需设置。 我正在使用SSL重定向,因此我将确保客户端知道这一点,并添加一个测试:

public TestingMvcFunctionalTests(WebApplicationTestFixture<Startup> fixture)
{
Client = fixture.Client;
Client.BaseAddress = new Uri("https://localhost");
}

[Fact]
public async Task GetHomePage()
{
// Arrange & Act
var response = await Client.GetAsync("/");

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}

This will fail, in fact. Because I have an API Key that is needed to call out to my backend system, and I store it in .NET's User Secrets system. My test will get an InternalServerError instead of OK.

实际上,这将失败。 因为我有一个调用后端系统所需的API密钥,所以我将其存储在.NET的User Secrets系统中。 我的测试将收到InternalServerError而不是OK。

Starting test execution, please wait...
[xUnit.net 00:00:01.2110048] Discovering: hanselminutes.core.tests
[xUnit.net 00:00:01.2690390] Discovered: hanselminutes.core.tests
[xUnit.net 00:00:01.2749018] Starting: hanselminutes.core.tests
[xUnit.net 00:00:08.1088832] hanselminutes_core_tests.TestingMvcFunctionalTests.GetHomePage [FAIL]
[xUnit.net 00:00:08.1102884] Assert.Equal() Failure
[xUnit.net 00:00:08.1103719] Expected: OK
[xUnit.net 00:00:08.1104377] Actual: InternalServerError
[xUnit.net 00:00:08.1114432] Stack Trace:
[xUnit.net 00:00:08.1124268] D:\github\hanselminutes-core\hanselminutes.core.tests\FunctionalTests.cs(29,0): at hanselminutes_core_tests.TestingMvcFunctionalTests.<GetHomePage>d__4.MoveNext()
[xUnit.net 00:00:08.1126872] --- End of stack trace from previous location where exception was thrown ---
[xUnit.net 00:00:08.1158250] Finished: hanselminutes.core.tests
Failed hanselminutes_core_tests.TestingMvcFunctionalTests.GetHomePage
Error Message:
Assert.Equal() Failure
Expected: OK
Actual: InternalServerError

Where do these secrets come from? In Development they come from user secrets.

这些秘密从何而来? 在开发中,它们来自用户机密。

public Startup(IHostingEnvironment env)
{
this.env = env;
var builder = new ConfigurationBuilder();

if (env.IsDevelopment())
{
builder.AddUserSecrets<Startup>();
}
Configuration = builder.Build();
}

But in Production they come from the ENVIRONMENT. Are these tests Development or Production...I must ask myself.  They are Production unless told otherwise. I can override the Fixture and tell it to use another Environment, like "Development." Here is a way (given this preview) to make my own TestFixture by deriving and grabbing and override to change the Environment. I think it's too hard and should be easier.

但是在生产中,它们来自环境。 这些测试是开发还是生产...我必须问自己。 除非另有说明,否则它们是生产型。 我可以覆盖灯具,并告诉它使用另一个环境,例如“开发”。 这是通过派生,获取和覆盖以更改环境来制作自己的TestFixture的一种方法(提供此预览)。 我认为这太难了,应该会更容易

Either way, the real question here is for me - do I want my tests to be integration tests in development or in "production." Likely I need to make a new environment for myself - "testing."

无论哪种方式,这里真正的问题是对我来说-我希望我的测试是开发中还是“生产”中的集成测试。 我可能需要为自己创造一个新的环境-“测试”。

public class MyOwnTextFixture<TStartup> : WebApplicationTestFixture<Startup> where TStartup : class
{
public MyOwnTextFixture() { }

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Development");
}
}

However, my User Secrets still aren't loading, and that's where the API Key is that I need.

但是,我的用户密钥仍然没有加载,这就是我需要的API密钥。

BUG?: There is either a bug here, or I don't know what I'm doing. I'm loading User Secrets in builder.AddUserSecrets<Startup> and later injecting the IConfiguration instance from builder.Build() and going "_apiKey = config["SimpleCastAPIKey"];" but it's null. The config that's injected later in the app isn't the same one that's created in Startup.cs. It's empty. Not sure if this is an ASP.NE Core 2.0 thing or 2.1 thing but I'm going to bring it up with the team and update this blog post later. It might be a Razor Pages subtlety I'm missing.For now, I'm going to put in a check and manually fix up my Config. However, when this is fixed (or I discover my error) this whole thing will be a pretty nice little set up for integration testing.

BUG ?:这里有一个错误,或者我不知道自己在做什么。 我在builder.AddUserSecrets <Startup>中加载用户密钥,然后从builder.Build()注入IConfiguration实例,然后输入“ _apiKey = config [” SimpleCastAPIKey“]; ”,但它为空。 稍后在应用程序中注入的配置与Startup.cs中创建的配置不同。 它是空的。 不确定这是ASP.NE Core 2.0还是2.1,但我将与团队讨论并稍后更新此博客文章。 我可能缺少Razor Pages的细微之处。现在,我要进行检查并手动修复Config。 但是,当这个问题解决之后(或者我发现了我的错误),这整个过程将成为集成测试的一个不错的设置。

I will add another test, similar to the redirect Unit Test but a fuller integration test that actually uses HTTP and tests the result.

我将添加另一个测试,类似于重定向单元测试,但实际上是使用HTTP并测试结果的更完整的集成测试。

[Fact]
public async Task GetAShow()
{
// Arrange & Act
var response = await Client.GetAsync("/620");

// Assert
Assert.Equal(HttpStatusCode.MovedPermanently, response.StatusCode);
Assert.Equal("/620/jessica-rose-and-the-worst-advice-ever",response.Headers.Location.ToString());
}

There's another issue here that I don't understand. Because have to set Client.BaseAddress to https://localhost (because https) and the Client is passed into fixture.Client, I can't set the Base address twice or I'll get an exception, as the Test's Constructor runs twice, but the HttpClient that's passed in as a lifecycler that's longer. It's being reused, and it fails when setting its BaseAddress twice.

这里还有另一个我不明白的问题。 因为必须将Client.BaseAddress设置为https:// localhost (因为https),并且Client会传递到Fixture.Client中,所以我不能两次设置Base地址,否则会得到异常,因为Test的构造函数运行两次,但作为生命周期传递程序传递的HttpClient更长。 它被重用,并且在两次设置其BaseAddress时失败。

Error Message:
System.InvalidOperationException : This instance has already started one or more requests. Properties can only be modified before sending the first request.

BUG? So to work around it I check to see if I've done it before. Which is gross. I want to set the BaseAddress once, but I am not in charge of the creation of this HttpClient as it's passed in by the Fixture.

BUG? 因此,要解决此问题,请检查是否之前已完成。 哪个好我想设置一次BaseAddress,但是由于该Fixture传递了该HttpClient,因此我不负责该HttpClient的创建。

public TestingMvcFunctionalTests(MyOwnTextFixture<Startup> fixture)
{
Client = fixture.Client;
if (Client.BaseAddress.ToString().StartsWith("https://") == false)
Client.BaseAddress = new Uri("https://localhost");
}

Another option is that I create a new client every time, which is less efficient and perhaps a better idea as it avoids any side effects from other tests, but also feels weird that I should have to do this, as the new standard for ASP.NET Core sites is to be SSL/HTTPS by default..

另一个选择是,我每次都创建一个新客户端,这效率较低,可能是一个更好的主意,因为它避免了其他测试带来的任何副作用,但是我感到很奇怪,我必须这样做,这是ASP的新标准。 NET Core站点默认为SSL / HTTPS。

public TestingMvcFunctionalTests(MyOwnTextFixture<Startup> fixture)
{
Client = fixture.CreateClient(new Uri(https://localhost));
}

I'm still learning about how it all fits together, but later I plan to add in Selenium tests to have a full, complete, test suite that includes the browser, CSS, JavaScript, end-to-end integration tests, and unit tests.

我仍在学习如何将它们组合在一起,但后来我计划添加Selenium测试以拥有完整,完整的测试套件,其中包括浏览器,CSS,JavaScript,端到端集成测试和单元测试。 。

Let me know if you think I'm doing something wrong. This is preview stuff, so it's early days!

如果您认为我做错了事,请告诉我。 这是预览资料,所以还很早!

Sponsor: Get the latest JetBrains Rider for debugging third-party .NET code, Smart Step Into, more debugger improvements, C# Interactive, new project wizard, and formatting code in columns.

赞助商:获取最新的JetBrains Rider,用于调试第三方.NET代码,Smart Step Into,更多调试器改进,C#Interactive,新项目向导以及列中的格式代码。

翻译自: https://www.hanselman.com/blog/easier-functional-and-integration-testing-of-aspnet-core-applications

asp.net 集成测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值