单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常情况下,一个单元测试(用例)用于判断某个特定条件(或场景)下特定函数的行为。如果想对单元测试的好处有更多的了解,可以看一下单元测试实战。
在.NET社区内,NUnit无疑是最经典的单元测试工具,要了解它的用法,建议看一下园子里的一篇很棒的文章NUnit详细使用方法。本文对此不再赘述。另外MbUnit作为后起之秀,也很值得一试。
在F#中, LOP(Language-Oriented Programming)是它的一个亮点,而FsUnit则是LOP的一个很好的实践。FsUnit使用F#开发,用它编写的测试用例会接近于自然语言(英语),在其中我们也可以看到F#对函数进行组合的强大威力。
在本文中,我将通过简单的例子分别对NUnit和FsUnit的基本用法进行介绍。假定我们在开发一个类库MyFsLib,其中有一个模块mathHelper,里面有一些关于数学的函数,现在要做的就是测试这些函数。mathHelper的代码如下:
F# Code - mathHelper的签名
#light
module MyFsLib.MathHelper
/// 获取一个浮点数的平方值
val square: float -> float
/// 获取一个浮点数的立方值
val cube: float -> float
/// 判断一个整数是否为偶数
val isEven: int -> bool
/// 判断一个整数是否为奇数
val isOdd: int -> bool
/// 获取不大于指定正整数的质数数组
val generatePrimes: int -> int array
F# Code - mathHelper的实现
#light
module MyFsLib.MathHelper
open System
let pow x y = Math.Pow(x, y)
let square x = pow x 2.0
let cube x = pow x 3.0
let isEven x = x % 2 = 0
let isOdd x = x % 2 = 1
// Eratosthenes筛法
let generatePrimes n =
match n with
| _ when n < 2 -> [||]
| _ ->
// Init sieve.
let sieve = [| for i in 0 .. n do yield true |]
let isPrime index = sieve.[index]
// Check it.
let upperBound = Convert.ToInt32(Math.Sqrt((float)n))
for i = 2 to upperBound do
if isPrime i then
for j in [i * 2 .. i .. sieve.Length - 1] do
sieve.[j] <- false
let mutable count = 0
for i = 2 to sieve.Length - 1 do
if isPrime i then
count <- count + 1
let primes = Array.create count 0
let mutable index = 0
for i = 2 to sieve.Length - 1 do
if isPrime i then
primes.[index] <- i
index <- index + 1
primes