.netcore持续集成测试篇之Xunit结合netcore内存服务器发送post请求

系列目录html

.net core集成测试之Post请求

Web项目中,不少与用户数据交互的请求都是Post请求,想必你们都用过HttpClient构造过post请求,这里并不对HttpClient作详细介绍,只介绍一些经常使用的功能.并结合AutoFixture演示如何自动构造请求数据,简单手动建立Json或者Formdata的工做量,提升生产效率.web

咱们为上节建立的HelloWorld控制器添加一个StudentInfo方法,内容以下json

[HttpPost]
        public IActionResult StudentInfo(Student student)
        {
            return Content(student.Name);
        }

这个方法的参数是一个Student类型的对象,和早期版本mvc并无太大差异,咱们把这个Student类的代码贴出来:后端

public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public byte Gender { get; set; }
        public string School { get; set; }
    }

下面咱们来构造一个对StudentInfo的请求测试方法.api

如何建立测试内存服务器的方法在第8节里有讲到,这里再也不讲,如下用到的都是测试服务器建立的HttpClient对象.浏览器

[Fact]
        public async Task SimplePost()
        {
            Dictionary<string, string> dict = new Dictionary<string, string>
            {
                {"name","sto"},
                {"age","32" },
                {"gender","2" },
                {"school","middleschool" }
            };
            var response = await _client.PostAsync("/HelloWorld/StudentInfo", new FormUrlEncodedContent(dict));
            response.EnsureSuccessStatusCode();
            var result =await response.Content.ReadAsStringAsync();
            Assert.Equal("sto", result);
        }

以上代码可能你们都很是熟悉了.咱们用dictionary对象构造了formdata而后作为post请求内容发送到服务端,服务端返回的是接收到的student对象的name属性,这里咱们验证服务端返回的name是否是咱们传过去的"sto".服务器

然而这样作是很是耗时的,若是只写一两个测试方法还好,对成千上百个方法这样构建参数是很是繁琐和乏味的,而且若是后端对数据有限制的状况下想构造出来符合条件的数据更是麻烦,而且后端接口若是字段有修改则有可能形成测试失败.因为测试项目引用了mvc项目,所以咱们能够访问到mvc项目里的这些类型,而后使用AutoFixture动态建立这些类型的实例,而后序列化为Json提交,这样会明显减小工做量并增长程序的可维护性.mvc

AutoFixture的安装前面也提到过,而且它是支持.net core的,咱们在Nuget包管理工具界面输入AutoFixture.Xunit2进行搜索,而后下载这个包便可,若是直接下载它则不用下载AutoFixture包,由于它是这个包的一个依赖,会自动安装.app

改造后的方法以下:asp.net

[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));
        }

首先fact注解变成了Theory注解,咱们知道要为测试方法添加参数须要使用Theory注解,下面添加了AutoData注解,添加之后AutoFixture就会自动为方法的参数提供值.

下面咱们把stud对象序列化为json字符串,而后包装成一个stringcontent对象提交到后台,因为传入的是什么值是AutoFixture随机建立的,咱们并不知道,所以不能像上面同样断言它是"sto",可是它必定是有值的,所以咱们断言它不是null或者空字符串.

然而遗憾的是,以上测试却没有经过,咱们看一下错误面板信息:

avatar
经过面板信息咱们看到AutoFixture构建的对象Name里是有值的,然而却返回的False,咱们只知道结果,其中的过程咱们并不清楚,也很难直观的看到错误缘由,这时候咱们使用调试模式来启动测试程序

首先咱们在测试方法刚进入的时候打上断点,看看传入的有没有值
avatar

进入mvc项目,在方法刚进入的地方也打上断点
avatar

下面咱们对测试方法执行调试

测试方法如何调试在前面的章节中已经讲过,咱们在Test Explorer面板里找到这个方法而后右键点击它的名字,在右键菜单里选择"调试单元测试",更为简单的方法是,若是一个测试方法执行失败,则在它的方法定义上会出现一个红叉

avatar
咱们点击这个红叉就会出现一个浮动面板

avatar
下面有两个按钮一个是运行一个是调试,点击调试就能够进入调试模式了.

第一个断点处咱们看到stud的每个字段都是有值的

avatar

按下F5继续,进入mvc方法里的断点
avatar
咱们看到这里每一个字段绑定的都是默认值,也就是咱们传入的值并无绑定成功.

以上的调试是为了展现如何调试mvc测试项目,以上单步调试并不能帮助咱们太多,实际上是由于.net core mvc改变了以往的绑定方式,改为了webapi 2.0的绑定方式,也就是要显式的给参数加上FromBody注解方可成功绑定json数据

前面的示例咱们看到formData是不须要注解就能够成功绑定的

咱们改一下Mvc里的方法,增长一个frombody注解

[HttpPost]
        public IActionResult StudentInfo([FromBody]Student student)
        {
            return Content(student.Name);
        }

咱们再次运行,就可以正确绑定值了.

注意,不少人会想,是否是加了frombody注解之后即可以接收formdata类型的参数,又能接收json类型参数呢,其实答案是否认的,若是加上了frombody后再提供formdata类型参数,则会返回415不支持的格式错误.所以这里要权衡,若是是传统的mvc项目经过form提交,则不能添加frombody,固然有一些插件能够把form序列化为json,这样就能够了.

有引发朋友可能会有疑惑,我直接从浏览器发送请求或者使用postman工具就好了,干吗这么费劲呢?这样作的意义何在呢?其实前面也说到过,使用postman或者其它工具请求一方面不利于自动化测试(固然,postman是能够作到的)另外一方面这样作依赖于外部web服务器,若是有多个环境在发布更新的时候遗漏了某一个环境就会形成测试结果的不稳定,而且测试环境迁移了,测试项目也要跟着迁移,增长了维护成本.使用asp.net core自身的内存web服务器功能则彻底不依赖于外部web服务器或者外部测试工具,测试时自动启动web服务器,测试完成本身销毁,极大地方便了持续测试.