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程序员们,经过简单的重构,咱们解放了本身。