目录

编写基于Property-based的单元测试

使用FsCheck编写Property-based测试

在Xunit中使用FsCheck

使用FsCheck编写Model-based测试-待续

无论是Xunit还是Nunit都有额外的扩展用来编写FsCheck测试,以Xunit为例 :

Install-Package FsCheck.Xunit -Version 2.13.0

不同于普通的Xunit测试,一般的测试需要标记[Fact],你需要使用[Property]标记FsCheck测试。给定一个函数:

private int Add(int x, int y)
{
return x + y;
}

针对加法交换律编写一个Property-based测试:

[Property]
public bool Commutative(int x, int y)
{
return Add(x, y) == Add(y, x);
}

F#

[<Property>]
let Commutative x y =
add x y = add y x

在之前的例子里,我们介绍了什么是Property-based测试,然后花了一篇博客介绍了各种各样的Generator,每一个刚开始了解Property-based测试的人都会觉得这种方案很有意思,但是当你真正开始编写Property-base测试的时候你就会感觉得无从下手,应该断言什么样的Properties呢?

这篇文章介绍一些Properties供你参考:

1. 不同的执行顺序,同样的执行结果

例如被测函数为List.OrderBy,如果我们在List.OrderBy函数之前执行一个操作Add1,然后执行List.OrderBy函数。结果应该等于先执行List.OrderBy函数再执行操作Add1

 [Property]
public bool AddOneThenSortShouldSameAsSortThenAddOne(List<int> list)
{
var result1 = list.OrderBy(x => x).Select(Add1);
var result2 = list.Select(Add1).OrderBy(x => x); return result1.SequenceEqual(result2);
}

F#

 [<Property(Verbose=true)>]
let ``+1 then sort should be same as sort then +1`` aList =
let add1 x = x + 1 let result1 = aList |> List.sort |> List.map add1
let result2 = aList |> List.map add1 |> List.sort result1 = result2

2.连续执行操作,结果跟之前一致

例如List.Reverse函数,连续执行两次,结果跟期初是一样的。类似的函数如序列化和反序列化,Redo和Undo。

[Property]
public bool ReverseThenReverseShouldSameAsOriginal(int[] list)
{
var result= list.Reverse().Reverse();
return result.SequenceEqual(list);
}

F#

[<Property>]
let ``reverse then reverse should be same as original``
(aList:int list) =
let reverseThenReverse = aList |> List.rev |> List.rev
reverseThenReverse = aList

3. 有一些属性是永远不会改变的

在数据变化过程中,有一些属性是永远不会改变的,例如Sort操作,前后数据的Length总是不变的,这一属性可以作为Property-based测试的一个依据:

public bool SomethingNeverChanged(List<int> list)
{
var result = list.OrderBy(x => x);
return result.Count() == list.Count;
}

F#

let ``sort should have same length as original`` (aList:int list) =
let sorted = aList |> List.sort
List.length sorted = List.length aList

为OO代码编写Property-based测试

接下来我们尝试针对一个OO的例子编写Property-based测试:

public class Dollar
{
private int _amount; public Dollar(int amount)
{
_amount = amount;
} public int Amount => _amount; public void Add(int add)
{
_amount = _amount + add;
} public void Multiplier(int multiplier)
{
_amount = _amount * multiplier;
} public static Dollar Create(int amount)
{
return new Dollar(amount);
}
}

F#

type Dollar(amount : int) =
let mutable privateAmount = amount; member this.Amount = privateAmount
member this.Add add =
privateAmount <- this.Amount + add
member this.Times multiplier =
privateAmount <- this.Amount * multiplier
static member Create amount =
Dollar amount

Dollar类主要有两个方法,Add和Multiplier分别用来修改私有变量_amount。如何测试Dollar类呢?都有哪些Properties可用?调用Add方法后再读取Amount的值应该是同一个值:

[Property]
public bool SetAndGetShouldGiveSameResult(int amount)
{
var dollar = Dollar.Create(0);
dollar.Add(amount); return dollar.Amount == amount;
}

F#

[<Property>]
let ``set then get should give same result`` value =
let obj = Dollar.Create 0
obj.Add value
let newValue = obj.Amount
value = newValue

还有什么Property可供使用呢,Add和Multiplier两个方法执行完毕的结果等价于直接Create:

[Property]
public bool AddThenMultiplierSameAsCreate(int start, int times)
{
var dollar = Dollar.Create(0);
dollar.Add(start);
dollar.Multiplier(times); var dollar2 = Dollar.Create(start * times); return dollar.Amount == dollar2.Amount;
}

F#

 [<Property>]
let ``add then multiplier same as create`` value times =
let dollar = Dollar.Create 0
dollar.Add value
dollar.Times times let dollar2 = Dollar.Create(value*times); dollar.Amount = dollar2.Amount

编写自定义Generator

迄今为止,我们都在使用FsCheck自带的Generator,而在实际项目开发过程中,你还需要生成自定义的Generator供你使用,例如有一个User类型:

public class User
{
public string Name { get; set; } public int Age { get; set; }
}

自定义Generator:

public class UserArbitrary: Arbitrary<User>
{
public override Gen<User> Generator =>
from x in Arb.Generate<string>()
from int y in Gen.Choose(20, 30)
where x != string.Empty
select new User {Name = x, Age = y};
}

最后还要将自定义的Arbitrary注册在FsCheck中:

public class MyGenerators {
public static Arbitrary<User> User() {
return new UserArbitrary();
}
} Arb.Register<MyGenerators>();

写个例子试试:

[Property]
public bool GenerateUsers(User user)
{
return user.Name != string.Empty;
}

所以代码实例均可以在github下载

在Xunit中使用FsCheck的更多相关文章

  1. 在 XUnit 中使用依赖注入

    在 XUnit 中使用依赖注入 Intro 之前写过一篇 xunit 的依赖注入相关的文章,但是实际使用起来不是那么方便 今天介绍一个基于xunit和微软依赖注入框架的"真正"的依 ...

  2. 更优雅的在 Xunit 中使用依赖注入

    Xunit.DependencyInjection 7.0 发布了 Intro 上次我们已经介绍过一次大师的 Xunit.DependencyInjection https://www.cnblogs ...

  3. 使用hangfire在xunit中

    框架为:abp hangfire配置连接:https://aspnetboilerplate.com/Pages/Documents/Hangfire-Integration 在单元测试中如何配置呢? ...

  4. 舍弃Nunit拥抱Xunit

    前言 今天与同事在讨论.Net下测试框架的时候,说到NUnit等大多数测试框架的SetUp以及TearDown方法并不是显得那么完美,所以在公司内部的项目中采用了Xunit框架.那么究竟是什么样的原因 ...

  5. xUnit安装及注意事项

    前言 对于单元测试,想必大家都已再熟悉不过了,同时单元测试的重要性也越发突出,在招聘中也特别强调单元测试,但是对于微软内置的单元测试还是太过于繁琐,于是都在寻找一种简洁并且更加轻量的测试工具.用的最多 ...

  6. DNX/ASP.NET 5的xUnit入门向导

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:想必很多人已经和我一样在使用ASP.NET 5开发真实世界的应用了,那么做好单元测试和 ...

  7. .NET Core: 在.NET Core中进行单元测试

    单元测试能够帮助开发人员确保所开发的模块.类以及类中的方法等的正确性,在项目开发过程中,及时进行单元测试能够避免不必要的BUG以及提高测试效率. 在本文中,我们会分别来学习如何使用MSTest.xUn ...

  8. XUnit 依赖注入

    XUnit 依赖注入 Intro 现在的开发中越来越看重依赖注入的思想,微软的 Asp.Net Core 框架更是天然集成了依赖注入,那么在单元测试中如何使用依赖注入呢? 本文主要介绍如何通过 XUn ...

  9. Xunit和Nunit的区别

    https://www.cnblogs.com/Leo_wl/p/5727712.html 舍弃Nunit拥抱Xunit   前言 今天与同事在讨论.Net下测试框架的时候,说到NUnit等大多数测试 ...

随机推荐

  1. APP版本更新通知流程测试要点

    一.APP版本更新通知流程图如下: 二.测试注意点: 1.Android更新直接下载APK,IOS引导至APP Store更新页面: 强制更新------只有"立即更新" 1.一般 ...

  2. 深入浅出java常量池

    理论 jvm虚拟内存分布:      程序计数器是jvm执行程序的流水线,存放一些跳转指令.      本地方法栈是jvm调用操作系统方法所使用的栈.      虚拟机栈是jvm执行java代码所使用 ...

  3. django 的时区设置

    在Django的配置文件settings.py中,有两个配置参数是跟时间与时区有关的,分别是TIME_ZONE和USE_TZ 如果USE_TZ设置为True时,Django会使用系统默认设置的时区,即 ...

  4. TF.learn学习

    官网地址:https://www.tensorflow.org/versions/r1.1/get_started/tflearn 1.代码例子 实现自定义的Estimator 使用DNNClassi ...

  5. Spark学习之Spark调优与调试(二)

    下面来看看更复杂的情况,比如,当调度器进行流水线执行(pipelining),或把多个 RDD 合并到一个步骤中时.当RDD 不需要混洗数据就可以从父节点计算出来时,调度器就会自动进行流水线执行.上一 ...

  6. Python中使用面状矢量裁剪栅格影像,并依据Value值更改矢量属性

    本文整体思路:在Python中使用Geopandas库,依次读取shp文件的每一个面状要素,获取其空间边界信息并裁剪对应的栅格影像,计算所裁剪影像Value值的众数,将其设置为对应面状要素的NewTY ...

  7. Android Studio Run项目出现Failure [INSTALL_FAILED_TEST_ONLY]

    同名掘金博文:https://juejin.im/post/5c2e0c496fb9a049a711f09a 运行环境: AS 版 本:Android Studio 3.2.1 手机型号:vivo Y ...

  8. angular开发环境搭建及新建项目

    最近一个星期准备学习一下angular前端框架,因为之前在学习abp框架的时候,都要求前端要掌握angular,所以不得不回来恶补一下了,学习的过程有时间的话会记录在这里,方便以后复习. 闲言少叙,下 ...

  9. 基于ArcGISServer进行分页矢量查询的方案进阶

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.    背景 在空间查询中,我们对查询结果要求以分页形式进行展示.G ...

  10. 虹软人脸识别ArcFace2.0 Android SDK使用教程

    一.获取SDK 1.进入ArcFace2.0的申请地址 https://ai.arcsoft.com.cn/product/arcface.html 2.填写信息申请并提交 申请通过后即可下载SDK, ...