.netcore持续集成测试篇之测试方法改造

通过前面两节讲解,我们的测试类中已经有两个测试方法了,总体上如下

public class mvc20 { private readonly HttpClient _client; public mvc20() { var builder = new WebHostBuilder() .UseContentRoot(@"E:\personal project\newTest2018\ConsoleApp1\CoreMvc") .UseEnvironment("Development") .UseStartup<CoreMvc.Startup>(); var server = new TestServer(builder); _client = server.CreateClient(); } [Fact] public async Task SimpleGet() { var response = await _client.GetAsync("/HelloWorld/Hello"); response.EnsureSuccessStatusCode(); var responseStr = await response.Content.ReadAsStringAsync(); Assert.Equal("Hello,World", responseStr); } [Theory] [AutoData] public async Task SimplePost(Student stud) { var content = new StringContent(JsonConvert.SerializeObject(stud), Encoding.UTF8, "application/json"); var response = await _client.PostAsync("/HelloWorld/StudentInfo", content); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.True(!string.IsNullOrEmpty(result)); } } 改进一:将对象初始化移到外部类中

以上方法看似没有问题,实际上却有一个性能陷阱,我们通过前面章节的知识已经知道,xunit里测试类的构造函数会在每一个测试方法运行的时候都执行一遍,通常情况下我们的测试代码远不止三几个,有时候几十个甚至上百个.这样每次都创建一个是非常影响性能的.并且这里的TestServer和_client都没有释放.此外就是web项目里可能每一个测试类都需要创建这样一个TestServer,这样重复的代码会复制很多次,带来维护困难.

我们前面讲到过,我们如果想要让一个对象在一个测试类中只初始化一次,就要让这个类实现IClassFixture泛型接口,类在初始化的时候会自动注入这个泛型对象的实体,并且只初始化一次,如果这个泛型对象实现了IDisposable接口,则会在测试类所有方法都执行完成的时候执行这个对象里的Dispose方法.

首先我们创建一个名为MyTestServerFixtrue的类,TestServer和HttpClient对象的初始化在这里执行.代码如下

public class MyTestServerFixtrue:IDisposable { public readonly HttpClient _client; private readonly TestServer _server; public MyTestServerFixtrue() { var builder = new WebHostBuilder() .UseContentRoot(@"E:\personal project\newTest2018\ConsoleApp1\CoreMvc") .UseEnvironment("Development") .UseStartup<CoreMvc.Startup>(); _server = new TestServer(builder); _client = _server.CreateClient(); } public void Dispose() { _client.Dispose(); _server.Dispose(); }

这里的方法和参数大部分都和前面在测试类中添加的一样,只是有以下几点需要注意:
1.把server变量放在构造函数外边,这样我们才能在Dispose里把它释放掉,不然无法定位到它.
2.把client变成public类型,因为我们需要在测试类中访问它.

下面我们再看测试类改造后的代码

public class mvc20:IClassFixture<MyTestServerFixtrue> { private readonly HttpClient _client; public mvc20(MyTestServerFixtrue fixtrue) { this._client = fixtrue._client; } }

这里是主要代码,首先这个实现了IClassFixture,然后我们把无参构造函数改变成有参的,并且传入MyTestServerFixtrue类型对象,Xunit会自动注入这个对象,然后我们把这个对象里的httpclient赋值给本类的_client对象,这样我们就可以在本类中使用它了.

这样其它的测试类也可以实现IClassFixture<MyTestServerFixtrue>,如果想要改TestServer的配置只需要在MyTestServerFixtrue类中改就行了.

改进二:固定路由参数

我们看到前面讲到的两个测试方法提交的路径中都包含"/HelloWorld",它其实匹配控制器名,一般情况下同一个Controller下的方法的测试方法都写在同一个测试类中.这样Controller名称是固定的,我们可以把它单独抽离出来,只需要Action后面的路由.

我们把测试类改成如下:

public class mvc20:IClassFixture<MyTestServerFixtrue> { private readonly HttpClient _client; public mvc20(MyTestServerFixtrue fixtrue) { var baseAddr = fixtrue._client.BaseAddress.AbsoluteUri; string controllerName ="HelloWorld"; this._client = fixtrue._client; if (!fixtrue._client.BaseAddress.AbsoluteUri.Contains(controllerName)) { fixtrue._client.BaseAddress = new Uri(baseAddr + controllerName+"http://www.likecs.com/"); } } [Fact] public async Task SimpleGet() { var response = await _client.GetAsync($"{nameof(HelloWorldController.Hello)}"); response.EnsureSuccessStatusCode(); var responseStr = await response.Content.ReadAsStringAsync(); Assert.Equal("Hello,World", responseStr); } [Theory] [AutoData] public async Task SimplePost(Student stud) { var content = new StringContent(JsonConvert.SerializeObject(stud), Encoding.UTF8, "application/json"); var response = await _client.PostAsync($"{nameof(HelloWorldController.StudentInfo)}", content); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); Assert.True(!string.IsNullOrEmpty(result)); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssdyp.html