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模式:

  1. Arrange:为测试准备
  2. Act:运行SUT(实际测试的代码)
  3. 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 测试的更多相关文章

  1. .NET Core系列 :3 、使用多个项目

    通过前面的两篇文章,我们已经知道如何创建新的项目,如何生成并运行我们的应用程序,也知道(大致) project.json 文件中的内容是什么意思.但大多数项目往往也需要多个项目或引用的类库.我们要创建 ...

  2. .NET Core系列 : 1、.NET Core 环境搭建和命令行CLI入门

    2016年6月27日.NET Core & ASP.NET Core 1.0在Redhat峰会上正式发布,社区里涌现了很多文章,我也计划写个系列文章,原因是.NET Core的入门门槛相当高, ...

  3. .Net Core 系列:2、ADO.Net 基础

    目录: 1.环境搭建 2.ADO.Net 基础 3.ASP.Net Core 基础 4.MD5.Sha256.AES 加密 5.实现登录注册功能 6.实现目录管理功能 7.实现文章发布.编辑.阅览和删 ...

  4. 拥抱.NET Core系列:MemoryCache 缓存域

    在上一篇“<拥抱.NET Core系列:MemoryCache 缓存选项>”我们介绍了一些 MSCache 的机制,今天我们来介绍一下 MSCache 中的缓存域. MSCache项目 M ...

  5. 老桂.net core系列课程

    为了支持"首届dnc开源峰会"(dncNew.com)顺利举办,本人<.net core系列课程>进行一波优惠,每个课程优惠在立即购买上方,领取现金券即可.课程地址为腾 ...

  6. asp.net core系列 40 Web 应用MVC 介绍与详细示例

    一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...

  7. asp.net core系列 39 Web 应用Razor 介绍与详细示例

    一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...

  8. asp.net core系列 36 WebAPI 搭建详细示例

    一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...

  9. 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)

    黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...

随机推荐

  1. 【CSS进阶】伪元素的妙用--单标签之美

    最近在研读 <CSS SECRET>(CSS揭秘)这本大作,对 CSS 有了更深层次的理解,折腾了下面这个项目: CSS3奇思妙想 -- Demo (请用 Chrome 浏览器打开,非常值 ...

  2. 07. Web大前端时代之:HTML5+CSS3入门系列~H5 地理位置

    Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 源码:https://github.com/duniti ...

  3. 15个关于Chrome的开发必备小技巧[译]

    谷歌Chrome,是当前最流行且被众多web开发人员使用的浏览器.最快六周就更新发布一次以及伴随着它不断强大的开发组件,使得Chrome成为你必备的开发工具.例如,在线编辑CSS,console以及d ...

  4. 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包

            微信支付教程系列之现金红包           最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...

  5. 应该是Angular2的一个bug?

    为了应对未来的趋势,及时赶上下一趟互联网技术,我最近也在通过具体项目研究angular2,首先必须要吐槽的是,学习angular2的成本本身不高,但是一堆的工具.配置实在让人 很是焦灼,就像asp.n ...

  6. c# 基础 object ,new操作符,类型转换

    参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...

  7. 【Java每日一题】20170104

    20170103问题解析请点击今日问题下方的"[Java每日一题]20170104"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  8. iOS之绘制虚线

    /*   ** lineFrame:     虚线的 frame   ** length:        虚线中短线的宽度   ** spacing:       虚线中短线之间的间距   ** co ...

  9. IT雇员及外包商选择:人品第一

    最近,苹果iOS操作系统和智能手机爆出了一个奇葩故障,在播放特定一段五秒钟的视频时能导致手机死机.唯一的解决办法是按住电源键和Home按键进行手机的重启. 第十八届中国国际高新技术成果交易会在深圳举办 ...

  10. Linux下编译安装Vim8.0

    什么是Vim? Vim 是经典的 UNIX 编辑器 Vi 的深度改良版本.它增加了许多功能,包括:多级撤销.格式高亮.命令行历史.在线帮助.拼写检查.文件名补完.块操作.脚本支持,等等.除了字符界面版 ...