Microsoft.NET 解決方案,項目開發必知必會。程序員
從這篇文章開始我將分享一系列我認爲在實際工做中頗有必要的一些.NET項目開發的核心技術點,因此我稱爲必知必會。儘管這一系列是使用.NET/C#來展示,可是一樣適用於其餘相似的OO技術平臺,這些技術點可能稱不上完整的技術,可是它是經驗的總結,是掉過多少坑以後的覺醒,因此有必要花幾分鐘時間記住它,在真實的項目開發中你就知道是多麼的有幫助。好了,廢話不說了,進入主題。測試
咱們在開發服務時爲了調試方便會在本地進行一個基本的模塊測試,你也能夠認爲是集成測試,只不過你的測試用例不會覆蓋到80%以上,而是一些咱們認爲在開發時不是很放心的點纔會編寫適當的用例來測試它。this
集成測試用例一般有多個執行上下文,對於咱們開發人員來講咱們的執行上下文一般都在本地,測試人員的上下文在測試環境中。開發人員的測試用來是不可以鏈接到其餘環境中去的(固然視具體狀況而定,有些用例很危險是不可以亂鏈接的,本文會講如何解決),開發人員運行的集成測試用例所要訪問的全部資源、服務都是在開發環境中的。這裏依然存在可是,可是爲了調試方便,咱們仍是須要可以在必要的時候鏈接到其餘環境中去調試問題,爲了可以真實的模擬出問題的環境、可真實的數據,咱們須要能有一個這樣的機制,在須要的時候我可以打開某個設置讓其可以切換集成測試運行的環境上下文,其實說白了就是你所要鏈接的環境、數據源的鏈接地址。spa
本篇文章咱們將經過一個簡單的實例來了解如何簡單的處理這中狀況,這其實基於對測試用來不斷重構後的效果。設計
1 using System; 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 4 namespace OrderManager.Test 5 { 6 using ProductService.Contract; 7 8 /// <summary> 9 /// Product service integration tests. 10 /// </summary> 11 [TestClass] 12 public class ProductServiceIntegrationTest 13 { 14 /// <summary> 15 /// service address. 16 /// </summary> 17 public const string ServiceAddress = "http://dev.service.ProductService/"; 18 19 /// <summary> 20 /// Product service get product by pid test. 21 /// </summary> 22 [TestMethod] 23 public void ProductService_GetProductByPid_Test() 24 { 25 var serviceInstance = ProductServiceClient.CreateClient(ServiceAddress); 26 var testResult = serviceInstance.GetProductByPid(0393844); 27 28 Assert.AreNotEqual(testResult, null); 29 Assert.AreEqual(testResult.Pid, 0393844); 30 } 31 } 32 }
這是一個實際的集成測試用例代碼,有一個當前測試類共用的服務地址,這個地址是DEV環境的,固然你也能夠定義其餘幾個環境的服務地址,前提是環境是容許你鏈接的,那纔有實際意義。調試
咱們來看測試用例,它是一個查詢方法測試用例,用來對ProductServiceClient.GetProductByPid服務方法進行測試,因爲面向查詢的操做是等幕的,不論咱們查詢多少次這個ID的Product,都不會對數據形成影響,可是若是咱們測試的是一個更新或者刪除就會帶來問題。code
在DEV環境中,測試更新、刪除用例沒有問題,可是若是你的機器是可以鏈接到遠程某個生產或者PRD測試上時會帶來必定的危險性,特別是在忙的時候,加班加點的幹進度,你很難記住你當前的機器的host配置中是否還鏈接着遠程的生產機器上,或者根本就不須要配置host就可以鏈接到某個你不該該鏈接的環境上。blog
這是目前的問題,那麼咱們如何解決這個問題呢 ,咱們經過對測試代碼進行一個簡單的重構就能夠避免因爲鏈接到不應鏈接的環境中運行危險的測試用例。索引
其實不少時候,重構真的可以幫助咱們找到出口,就比如俗話說的:"出口就在轉角處「,只有不斷重構纔可以逐漸的保證項目的質量,而這種效果是很可貴的。接口
提取抽象基類,對測試要訪問的環境進行明確的定義。
1 namespace OrderManager.Test 2 { 3 public abstract class ProductServiceIntegrationBase 4 { 5 /// <summary> 6 /// service address. 7 /// </summary> 8 protected const string ServiceAddressForDev = "http://dev.service.ProductService/"; 9 10 /// <summary> 11 /// service address. 12 /// </summary> 13 protected const string ServiceAddressForPrd = "http://Prd.service.ProductService/"; 14 15 /// <summary> 16 /// service address. 17 /// </summary> 18 protected const string ServiceAddressTest = "http://Test.service.ProductService/"; 19 } 20 }
對具體的測試類消除重複代碼,加入統一的構造方法。
1 using System; 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 4 namespace OrderManager.Test 5 { 6 using ProductService.Contract; 7 8 /// <summary> 9 /// Product service integration tests. 10 /// </summary> 11 [TestClass] 12 public class ProductServiceIntegrationTest : ProductServiceIntegrationBase 13 { 14 /// <summary> 15 /// product service client. 16 /// </summary> 17 private ProductServiceClient serviceInstance; 18 19 /// <summary> 20 /// Initialization test instance. 21 /// </summary> 22 [TestInitialize] 23 public void InitTestInstance() 24 { 25 serviceInstance = ProductServiceClient.CreateClient(ServiceAddressForDev/*for dev*/); 26 } 27 28 /// <summary> 29 /// Product service get product by pid test. 30 /// </summary> 31 [TestMethod] 32 public void ProductService_GetProductByPid_Test() 33 { 34 var testResult = serviceInstance.GetProductByPid(0393844); 35 36 Assert.AreNotEqual(testResult, null); 37 Assert.AreEqual(testResult.Pid, 0393844); 38 } 39 40 /// <summary> 41 /// Product service delete search index test. 42 /// </summary> 43 [TestMethod] 44 public void ProductService_DeleteProductSearchIndex_Test() 45 { 46 var testResult = serviceInstance.DeleteProductSearchIndex(); 47 48 Assert.IsTrue(testResult); 49 } 50 } 51 }
消除重複代碼後,咱們須要加入對具體測試用例檢查是否可以鏈接到某個環境中去。我加入了一個DeleteProductSearchIndex測試用例,該用例是用來測試刪除搜索索引的,這個測試用例只可以在本地DEV環境中運行(你可能以爲這個刪除接口不該該放在這個服務裏,這裏只是舉一個例子,無需糾結)。
爲了可以有一個檢查機制能提醒開發人員你目前鏈接的地址是哪個,咱們須要藉助於測試上下文。
重構後,咱們看一下如今的測試代碼結構。
1 using System; 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 4 namespace OrderManager.Test 5 { 6 using ProductService.Contract; 7 8 /// <summary> 9 /// Product service integration tests. 10 /// </summary> 11 [TestClass] 12 public class ProductServiceIntegrationTest : ProductServiceIntegrationBase 13 { 14 /// <summary> 15 /// product service client. 16 /// </summary> 17 private ProductServiceClient serviceInstance; 18 19 /// <summary> 20 /// Initialization test instance. 21 /// </summary> 22 [TestInitialize] 23 public void InitTestInstance() 24 { 25 serviceInstance = ProductServiceClient.CreateClient(ServiceAddressForPrd/*for dev*/); 26 27 this.CheckCurrentTestCaseIsRun(this.serviceInstance);//check current test case . 28 } 29 30 /// <summary> 31 /// Product service get product by pid test. 32 /// </summary> 33 [TestMethod] 34 public void ProductService_GetProductByPid_Test() 35 { 36 var testResult = serviceInstance.GetProductByPid(0393844); 37 38 Assert.AreNotEqual(testResult, null); 39 Assert.AreEqual(testResult.Pid, 0393844); 40 } 41 42 /// <summary> 43 /// Product service delete search index test. 44 /// </summary> 45 [TestMethod] 46 public void ProductService_DeleteProductSearchIndex_Test() 47 { 48 var testResult = serviceInstance.DeleteProductSearchIndex(); 49 50 Assert.IsTrue(testResult); 51 } 52 } 53 }
咱們加入了一個很重要的測試實例運行時方法InitTestInstance,該方法會在測試用例每次實例化時先執行,在方法內部有一個用來檢查當前測試用例運行的環境
this.CheckCurrentTestCaseIsRun(this.serviceInstance);//check current test case .,咱們轉到基類中。
1 using System; 2 using Microsoft.VisualStudio.TestTools.UnitTesting; 3 4 namespace OrderManager.Test 5 { 6 public abstract class ProductServiceIntegrationBase 7 { 8 /// <summary> 9 /// service address. 10 /// </summary> 11 protected const string ServiceAddressForDev = "http://dev.service.ProductService/"; 12 13 /// <summary> 14 /// get service address. 15 /// </summary> 16 protected const string ServiceAddressForPrd = "http://Prd.service.ProductService/"; 17 18 /// <summary> 19 /// service address. 20 /// </summary> 21 protected const string ServiceAddressTest = "http://Test.service.ProductService/"; 22 23 /// <summary> 24 /// Test context . 25 /// </summary> 26 public TestContext TestContext { get; set; } 27 28 /// <summary> 29 /// is check is run for current test case. 30 /// </summary> 31 protected void CheckCurrentTestCaseIsRun(ProductService.Contract.ProductServiceClient testObject) 32 { 33 if (testObject.ServiceAddress.Equals(ServiceAddressForPrd))// Prd 環境,須要當心檢查 34 { 35 if (this.TestContext.TestName.Equals("ProductService_DeleteProductSearchIndex_Test")) 36 Assert.IsTrue(false, "當前測試用例鏈接的環境爲PRD,請中止當前用例的運行。"); 37 } 38 else if (testObject.ServiceAddress.Equals(ServiceAddressTest))//Test 環境,檢查約定幾個用例 39 { 40 if (this.TestContext.TestName.Equals("ProductService_DeleteProductSearchIndex_Test")) 41 Assert.IsTrue(false, "當前測試用例鏈接的環境爲TEST,爲了避免破壞TEST環境,請中止用例的運行。"); 42 } 43 } 44 } 45 }
在檢查方法中咱們使用簡單的判斷某個用例不可以在PRD、TEST環境下執行,雖然判斷有點簡單,可是在真實的項目中足夠了,簡單有時候是一種設計思想。咱們運行全部的測試用例,查看各個狀態。
一目瞭然,更爲重要的是它不會影響你對其餘用例的執行。當你在深夜12點排查問題的時候,你很難控制本身的眼花、體虛致使的用例執行錯誤帶來的大問題,甚至是沒法挽回的的錯誤。
此文獻給那些跟我同樣的.NET程序員們,經過簡單的重構,咱們解放了本身。