系列目錄 <https://www.cnblogs.com/tylerzhou/p/11204826.html>
通過(guò)前面兩節(jié)講解,我們的測(cè)試類(lèi)中已經(jīng)有兩個(gè)測(cè)試方法了,總體上如下
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)); } }
改進(jìn)一:將對(duì)象初始化移到外部類(lèi)中
以上方法看似沒(méi)有問(wèn)題,實(shí)際上卻有一個(gè)性能陷阱,我們通過(guò)前面章節(jié)的知識(shí)已經(jīng)知道,xunit里測(cè)試類(lèi)的構(gòu)造函數(shù)會(huì)在每一個(gè)測(cè)試方法運(yùn)行的時(shí)候都執(zhí)行一遍,通常情況下我們的測(cè)試代碼遠(yuǎn)不止三幾個(gè),有時(shí)候幾十個(gè)甚至上百個(gè).這樣每次都創(chuàng)建一個(gè)是非常影響性能的.并且這里的TestServer和_client都沒(méi)有釋放.此外就是web項(xiàng)目里可能每一個(gè)測(cè)試類(lèi)都需要?jiǎng)?chuàng)建這樣一個(gè)TestServer,這樣重復(fù)的代碼會(huì)復(fù)制很多次,帶來(lái)維護(hù)困難.
我們前面講到過(guò),我們?nèi)绻胍屢粋€(gè)對(duì)象在一個(gè)測(cè)試類(lèi)中只初始化一次,就要讓這個(gè)類(lèi)實(shí)現(xiàn)IClassFixture泛型接口,類(lèi)在初始化的時(shí)候會(huì)自動(dòng)注入這個(gè)泛型對(duì)象的實(shí)體,并且只初始化一次,如果這個(gè)泛型對(duì)象實(shí)現(xiàn)了IDisposable接口,則會(huì)在測(cè)試類(lèi)所有方法都執(zhí)行完成的時(shí)候執(zhí)行這個(gè)對(duì)象里的Dispose方法.
首先我們創(chuàng)建一個(gè)名為MyTestServerFixtrue的類(lèi),TestServer和HttpClient對(duì)象的初始化在這里執(zhí)行.代碼如下
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(); }
這里的方法和參數(shù)大部分都和前面在測(cè)試類(lèi)中添加的一樣,只是有以下幾點(diǎn)需要注意:
1.把server變量放在構(gòu)造函數(shù)外邊,這樣我們才能在Dispose里把它釋放掉,不然無(wú)法定位到它.
2.把client變成public類(lèi)型,因?yàn)槲覀冃枰跍y(cè)試類(lèi)中訪問(wèn)它.
下面我們?cè)倏礈y(cè)試類(lèi)改造后的代碼
public class mvc20:IClassFixture<MyTestServerFixtrue> { private readonly
HttpClient _client; public mvc20(MyTestServerFixtrue fixtrue) { this._client =
fixtrue._client; } }
這里是主要代碼,首先這個(gè)實(shí)現(xiàn)了IClassFixture,然后我們把無(wú)參構(gòu)造函數(shù)改變成有參的,并且傳入MyTestServerFixtrue類(lèi)型對(duì)象,Xunit會(huì)自動(dòng)注入這個(gè)對(duì)象,然后我們把這個(gè)對(duì)象里的httpclient賦值給本類(lèi)的_client對(duì)象,這樣我們就可以在本類(lèi)中使用它了.
這樣其它的測(cè)試類(lèi)也可以實(shí)現(xiàn)IClassFixture<MyTestServerFixtrue>
,如果想要改TestServer的配置只需要在MyTestServerFixtrue類(lèi)中改就行了.
改進(jìn)二:固定路由參數(shù)
我們看到前面講到的兩個(gè)測(cè)試方法提交的路徑中都包含"/HelloWorld",它其實(shí)匹配控制器名,一般情況下同一個(gè)Controller下的方法的測(cè)試方法都寫(xiě)在同一個(gè)測(cè)試類(lèi)中.這樣Controller名稱是固定的,我們可以把它單獨(dú)抽離出來(lái),只需要Action后面的路由.
我們把測(cè)試類(lèi)改成如下:
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+"/"); } }
[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)); } }
這里我們把controller的名稱加到HttpClient的BaseUrl里面,然后發(fā)送get,post等請(qǐng)求的時(shí)候只要Action的名字,這里我們使用nameof關(guān)鍵字來(lái)獲取action的名字,使用nameof關(guān)鍵字來(lái)獲取的好處是:第一,我們點(diǎn)擊方法名就可以快速定位到指定的方法.更為重要的是如果方法的名稱改了,編譯的時(shí)候就會(huì)出現(xiàn)編譯錯(cuò)誤,我們可以快速定位到錯(cuò)誤然后修改.
改進(jìn)三:資源路徑改為相對(duì)路徑
上面MyTestServerFixtrue類(lèi)中的代碼有一處有明顯問(wèn)題:那就是UseContentRoot里的路徑是寫(xiě)死的,項(xiàng)目在本機(jī)上地址與在服務(wù)器上的或者與其它同事的絕大多數(shù)情況下是不一樣的(因?yàn)榇蠹翼?xiàng)目所在的目錄名不相同)這時(shí)候如果其它人調(diào)用這些代碼就可能會(huì)出現(xiàn)錯(cuò)誤.
我們可以使用相對(duì)路徑來(lái)獲取絕對(duì)路來(lái)解決這個(gè)問(wèn)題,由于這兩個(gè)項(xiàng)目的主文件夾在同一文件夾下面,因此測(cè)試項(xiàng)目向外退若干層就能夠得到mvc項(xiàng)目的主目錄了.
我們將MyTestServerFixtrue類(lèi)的構(gòu)造方法改為如下:
public MyTestServerFixtrue() { var rootPath = GetContentRootDir(); var builder
= new WebHostBuilder() .UseContentRoot(rootPath) .UseEnvironment("Development")
.UseStartup<CoreMvc.Startup>(); _server = new TestServer(builder); _client =
_server.CreateClient(); }
這次我們不是再寫(xiě)死rootPath而是通過(guò)方法GetContentRootDir來(lái)獲取.
下面我們來(lái)看這個(gè)GetContentRootDir方法
private string GetContentRootDir() { var currentPath =
AppDomain.CurrentDomain.BaseDirectory; var relativePath =
@"..\..\..\..\CoreMvc"; var combinedPath = Path.Combine(currentPath,
relativePath); var absPath = Path.GetFullPath(combinedPath); return absPath; }
首先我們先獲取當(dāng)前程序域的目錄,也就是程序的運(yùn)行目錄,獲取到它之后我們看看向上移動(dòng)多少層能夠到達(dá)包含mvc項(xiàng)目和這個(gè)test項(xiàng)目的文件夾,經(jīng)查是四層,下面的相對(duì)路徑我們就寫(xiě)為如變量
relativePath定義的那樣.
我們把它們組合在一起,然后通過(guò)Path.GetFullPath來(lái)獲取到相對(duì)路徑的絕路徑.
改進(jìn)四 設(shè)置超時(shí)
有時(shí)候服務(wù)器故障會(huì)導(dǎo)致請(qǐng)求非常慢,服務(wù)器很長(zhǎng)時(shí)間無(wú)法返回請(qǐng)求,這就會(huì)導(dǎo)致集成測(cè)試代碼一直'卡'著無(wú)法完成,這時(shí)候可以設(shè)置一個(gè)超時(shí).設(shè)置非常簡(jiǎn)單,HttpClient有一個(gè)Timeout屬性,設(shè)置相應(yīng)的超時(shí)時(shí)間即可.HttpClient的默認(rèn)請(qǐng)求超時(shí)時(shí)間是100s,這個(gè)值應(yīng)該大部分時(shí)候不需要修改的,但是關(guān)于具體的業(yè)務(wù),可能有一些方法本身執(zhí)行時(shí)間特別長(zhǎng)(業(yè)務(wù)邏輯非常復(fù)雜,sql語(yǔ)句非常復(fù)雜等)這時(shí)候可以單元給本次請(qǐng)求設(shè)置一個(gè)超時(shí)時(shí)間.比如說(shuō)是150s,設(shè)置如下
CancellationTokenSource cts = new
CancellationTokenSource(TimeSpan.FromSeconds(150)); var response = await
client.GetAsync("/Home/index", cts.Token);
這里定義一個(gè)CancellationTokenSource對(duì)象,并指定超時(shí)時(shí)間,然后把此對(duì)象的Token對(duì)象傳給異步請(qǐng)求方法.
熱門(mén)工具 換一換

感谢您访问我们的网站,您可能还对以下资源感兴趣:
调教肉文小说-国产成本人片免费av-空姐av种子无码-在线观看免费午夜视频-综合久久精品激情-国产成人丝袜视频在线观看软件-大芭区三区四区无码-啊啊好爽啊啊插啊用力啊啊-wanch视频网-国产精品成人a免费观看