.NET Core系列 :4 测试
2016.6.27 微软已经正式发布了.NET Core 1.0 RTM,但是工具链还是预览版,同样的大量的开源测试库也都是至少发布了Alpha测试版支持.NET Core, 这篇文章 The State of .Net Core Testing Today 就将各个开源测试库的目前进展进行了汇总。本文我们的目的是在我们构建我们应用程序的时候能够进行测试,如何使用XUnit结合你可以通过为你的项目添加不同的测试用例NSubstitute进行单元测试,同时对整个项目进行集成测试。这次我们使用Visual Studio 2015 Update 3进行编写 。xUnit.net是基于.NET Framework 的开源测试工具。通过xUnit.net可以针对C#/F#/VB.NET等进行单元测试。ASP.NET Core 更直接把以往的Visual Studio Unit Test Framework 说再见了,而直接使用上了xUnit.net,xUnit.net基于NUnit 。从网站或者官网上,你可以找到不少xUnit的优点,与NUnit和其他测试框架相比有一下一些优势
1)为每个测试方法产生一个对象实例
2)取消了[SetUp]和[TearDown]
3)取消了[ExpectedException]
4)类似于Aspect的功能
5)减少了自定义属性(Attribute)的数目
6)采用泛型
7)匿名委托
8)可扩展的断言
9)可扩展的测试方法
10)可扩展的测试类
了解更多关于xUnit.net可以参考这里(点击打开链接[舍弃Nunit拥抱Xunit])。
使用xUnit.net 单元测试
首先我们类似于.NET Core系列 :3 、使用多个项目 创建一个解决方案testdemo,添加一个类库项目叫做DotnetCoreLib,Library.cs 也替换为:
namespace DotnetCoreLib
{
public class Calculator
{
public int Multi(int x, int y)
{
return x * y;
}
}
}
下面我们要创建一个针对DotnetCoreLib的测试项目,具体创建过程我们参照文章 https://github.com/dotnet/core-docs/tree/master/samples/core/getting-started/unit-testing-using-dotnet-test ,我们修改DotnetCoreLibTest 项目的project.json ,增加XUnit相关的nuget包引用,并修改部分配置。
还有我们设置Framework节点为 netcoreapp1.0, 依赖的xunit 和xunit.runner的包
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"DotnetCoreLib": {
"version": "1.0.0-*",
"target": "project"
},
"xunit": "2.2.0-beta2-build3300",
"xunit.runner.console": "2.2.0-beta2-build3300"
}
Calculator接下来就开始测试我们的类库Calculator, 修改Class1.cs为CalculatorTest.cs ,
using DotnetCoreLib;
using Xunit;
namespace DotnetCoreLibTest
{
public class CalTest
{
private readonly Calculator calculator;
public CalTest()
{
calculator = new Calculator();
}
[Fact]
public void OneMutiOneIsOne()
{
var result = calculator.Multi(1, 1);
Assert.Equal(1, result);
}
[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
public void ReturnValue(int value)
{
var result = calculator.Multi(1,value);
Assert.Equal(result, value);
}
}
}
上面的两个测试,我们分别用了2个特性[Fact] 和[Theory], [Fact]属性表示为一个方法的单个测试,[Theory]属性表示执行相同的代码,但是有不同的输入的参数的测试套件。[InlineData] 属性可用于指定为这些输入值。通过特性[Fact] 和[Theory],xUnit就理解了这是个测试方法,然后运行这个方法。在一个测试方法中,我们一般遵循包含三步骤的AAA模式:
- Arrange:为测试准备
- Act:运行SUT(实际测试的代码)
- Assert:校验结果
下面我们运行dotnet test 就可以看到结果了。
C:\Users\geffz\Documents\Visual Studio 2015\Projects\TestDemo\DotnetCoreLibTest>dotnet test
Project DotnetCoreLib (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Project DotnetCoreLibTest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit .NET Core win10-x64)
Discovering: DotnetCoreLibTest
Discovered: DotnetCoreLibTest
Starting: DotnetCoreLibTest
Finished: DotnetCoreLibTest
=== TEST EXECUTION SUMMARY ===
DotnetCoreLibTest Total: 4, Errors: 0, Failed: 0, Skipped: 0, Time: 0.206s
SUMMARY: Total: 1 targets, Passed: 1, Failed: 0.
上面的输出我们知道已经执行了4个测试,都通过了,[Face]特性标识表示固定输入的测试用例,而[Theory]特性标识表示可以指定多个输入的测试用例,结合InlineData特性标识使用。在上面的例子里,总共使用了三次InlineData特性标识,每次设定的值都不同,在执行单元测试时,设定的值会被测试框架赋值到对应的测试方法的参数里。你可以通过为你的项目添加不同的测试用例,这样就可以让你的代码得到充分测试。
xUnit.net 搭配NSubstitute 进行单元测试
在一个分层结构清晰的项目里,各层之间依赖于事先约定好的接口。在多人协作开发时,大多数人都只会负责自己的那一部分模块功能,开发进度通常情况下也不一致。当某个开发人员需要对自己的模块进行单元测试而依赖的其他模块还没有开发完成时,则需要对依赖的接口通过Mock的方式提供模拟功能,从而达到在不实际依赖其他模块的具体功能的情况下完成自己模块的单元测试工作。这时我们通常需要有一个单元测试模拟类库,一直以来,开发者对 mocking 类库的语法的简洁性有强烈的需求,NSubstitute 试图满足这一需求。简单明了的语法可以让我们将重心放在测试本身,而不是纠缠在测试替代实例的创建和配置上。NSubstitute 已尝试将最常用的操作需求简单化、易用化,并支持一些不常用的或探索性的功能,与此同时还尽可能地将其语法向自然语言靠近。关于NSubstitute的更详细信息请往 NSubstitute完全手册索引。
NSubstitute 已经发布2.0 RC版本支持.NET Core。引入NSubstitute 相关nuget包:
我们把Calculator 类重构下提取出接口ICalculator:
public interface ICalculator
{
int Multi(int x, int y);
}
我们可以让NSubstitute来创建类型实例的替代实例,可以创建诸如 Stub、Mock、Fake、Spy、Test Double 等,但当我们只是想要一个能有一定程度控制的替代实例时,为什么我们要困扰于此呢?我们可以告诉被创建的替代实例,当方法被调用时返回一个值:
[Fact]
public void Test_GetStarted_ReturnSpecifiedValue()
{
ICalculator calculator = Substitute.For<ICalculator>();
calculator.Multi(1, 2).Returns(2);
int actual = calculator.Multi(1, 2);
Assert.Equal(2, actual);
}
下面我们运行dotnet test 就可以看到结果了,增加了上面的2个用例,关于NSubstitute的更详细信息请往 NSubstitute完全手册索引。
集成测试
上面我们只是对逻辑进行了单元测试。对于Asp.Net Core项目,还需要模拟在网站部署的情况下对各个请求入口进行测试。NET Core 可为快速轻松集成测试提供非常棒的支持。
TestServer 类为 ASP.NET Core 中的集成测试执行大部分繁重操作,Microsoft.AspNetCore.TestHost 包中具有此类。本节内容来自于MSDN杂志《 ASP.NET Core - 实际的 ASP.NET Core MVC 筛选器》,这些集成测试不需要数据库或 Internet 连接或运行的 Web 服务器。它们如同单元测试一样快速简单,但最重要的是,它们允许你在整个请求管道中测试 ASP.NET 应用,而不只是控制器类中的孤立方法。建议尽可能编写单元测试,并针对无法单元测试的行为退回到集成测试,但使用此类高性能方式在 ASP.NET Core 中运行集成测试是非常棒的。
通过在一个工程里同时模拟了服务端(TestServer)和客户端(HttpClient)的通信,从而达到了整体测试WebApi接口的目的,相关的代码放在https://github.com/ardalis/GettingStartedWithFilters/tree/master/IntegrationTests 。文章对ASP.NET CORE MVC的筛选器进行测试,由于很难通过编写单元测试来测试此类场景,但是可以通过ASP.NET Core 的集成测试来达到相同的目的。
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Filters101;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
namespace IntegrationTests
{
public class AuthorsControllerTestBase
{
protected HttpClient GetClient()
{
var builder = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseEnvironment("Testing");
var server = new TestServer(builder);
var client = server.CreateClient();
// client always expects json results
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Filters101.Models;
using Newtonsoft.Json;
using Xunit;
namespace IntegrationTests.AuthorsController
{
public class Get : AuthorsControllerTestBase
{
private readonly HttpClient _client;
public Get()
{
_client = base.GetClient();
}
[Theory]
[InlineData("authors")]
[InlineData("authors2")]
public async Task ReturnsListOfAuthors(string controllerName)
{
var response = await _client.GetAsync($"/api/{controllerName}");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IEnumerable<Author>>(stringResponse).ToList();
Assert.Equal(2, result.Count());
Assert.Equal(1, result.Count(a => a.FullName == "Steve Smith"));
Assert.Equal(1, result.Count(a => a.FullName == "Neil Gaiman"));
}
}
}
此案例中的客户端是标准的 System.Net.Http.HttpClient,你可以使用它向服务器发出请求,正如同通过网络一样。但因为所有请求都在内存中进行,所以测试极其快速可靠。在cmd窗口执行单元测试,查看测试结果
.NET Core系列 :4 测试的更多相关文章
- .NET Core系列 :3 、使用多个项目
通过前面的两篇文章,我们已经知道如何创建新的项目,如何生成并运行我们的应用程序,也知道(大致) project.json 文件中的内容是什么意思.但大多数项目往往也需要多个项目或引用的类库.我们要创建 ...
- .NET Core系列 : 1、.NET Core 环境搭建和命令行CLI入门
2016年6月27日.NET Core & ASP.NET Core 1.0在Redhat峰会上正式发布,社区里涌现了很多文章,我也计划写个系列文章,原因是.NET Core的入门门槛相当高, ...
- .Net Core 系列:2、ADO.Net 基础
目录: 1.环境搭建 2.ADO.Net 基础 3.ASP.Net Core 基础 4.MD5.Sha256.AES 加密 5.实现登录注册功能 6.实现目录管理功能 7.实现文章发布.编辑.阅览和删 ...
- 拥抱.NET Core系列:MemoryCache 缓存域
在上一篇“<拥抱.NET Core系列:MemoryCache 缓存选项>”我们介绍了一些 MSCache 的机制,今天我们来介绍一下 MSCache 中的缓存域. MSCache项目 M ...
- 老桂.net core系列课程
为了支持"首届dnc开源峰会"(dncNew.com)顺利举办,本人<.net core系列课程>进行一波优惠,每个课程优惠在立即购买上方,领取现金券即可.课程地址为腾 ...
- asp.net core系列 40 Web 应用MVC 介绍与详细示例
一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
- asp.net core系列 39 Web 应用Razor 介绍与详细示例
一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...
- asp.net core系列 36 WebAPI 搭建详细示例
一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...
- 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)
黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...
随机推荐
- C# - 值类型、引用类型&走出误区,容易错误的说法
1. 值类型与引用类型小总结 1)对于引用类型的表达式(如一个变量),它的值是一个引用,而非对象. 2)引用就像URL,是允许你访问真实信息的一小片数据. 3)对于值类型的表达式,它的值是实际的数据. ...
- Word/Excel 在线预览
前言 近日项目中做到一个功能,需要上传附件后能够在线预览.之前也没做过这类似的,于是乎就查找了相关资料,.net实现Office文件预览大概有这几种方式: ① 使用Microsoft的Office组件 ...
- 9、 Struts2验证(声明式验证、自定义验证器)
1. 什么是Struts2 验证器 一个健壮的 web 应用程序必须确保用户输入是合法.有效的. Struts2 的输入验证 基于 XWork Validation Framework 的声明式验证: ...
- OpenCV人脸识别Eigen算法源码分析
1 理论基础 学习Eigen人脸识别算法需要了解一下它用到的几个理论基础,现总结如下: 1.1 协方差矩阵 首先需要了解一下公式: 共公式可以看出:均值描述的是样本集合的平均值,而标准差描述的则是样本 ...
- C#——传值参数(2)
//我的C#是跟着猛哥(刘铁猛)(算是我的正式老师)<C#语言入门详解>学习的,微信上猛哥也给我讲解了一些不懂得地方,对于我来说简直是一笔巨额财富,难得良师! 这次与大家共同学习C#中的 ...
- Javascript高性能编程-提高Dom访问速度
在浏览器中对于Dom的操作和普通的脚本的操作处于两个不同的dll中,两个dll的交互是比较耗时的,优化对Dom的操作可以提高脚本的执行速度.下面是对如何优化的一些总结: 将需要多次操作的节点存储在一个 ...
- RunLoop 总结:RunLoop的应用场景(一)
参考资料 好的书籍都是值得反复看的,那好的文章,好的资料也值得我们反复看.我们在不同的阶段来相同的文章或资料或书籍都能有不同的收获,那它就是好文章,好书籍,好资料.关于iOS 中的RunLoop资料非 ...
- git init和git init -bare区别
1 Git init 和 git init –bare 的区别 用"git init"初始化的版本库用户也可以在该目录下执行所有git方面的操作.但别的用户在将更新push上来的 ...
- asp.net core 负载均衡集群搭建(centos7+nginx+supervisor+kestrel)
概述 本文目的是搭建三台asp.net core 集群, 并配上 nginx做负载均衡 首先准备要运行的源码 http://pan.baidu.com/s/1c20x0bA 准备三台服务器(或则虚 ...
- 我的MYSQL学习心得(十四) 备份和恢复
我的MYSQL学习心得(十四) 备份和恢复 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...