F#探险之旅(七):在F#中进行单元测试

简介:

单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常情况下,一个单元测试(用例)用于判断某个特定条件(或场景)下特定函数的行为。如果想对单元测试的好处有更多的了解,可以看一下单元测试实战

在.NET社区内,NUnit无疑是最经典的单元测试工具,要了解它的用法,建议看一下园子里的一篇很棒的文章NUnit详细使用方法。本文对此不再赘述。另外MbUnit作为后起之秀,也很值得一试。

在F#中, LOPLanguage-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的实现


使用NUnit进行单元测试

不要害怕,由于F#植根于.NET平台的本性,你会发现这些测试用例代码都是那么眼熟。

需要废话的是,先添加对”nunit.framework.dll”的引用,而且要为测试类添加一个无参构造函数。

复制代码
F# Code - NUnit tester
#light
namespace NUnitTester

open NUnit.Framework
open MyFsLib

[<TestFixture
>]
type TestCases = class
new() = {}

[<Test
>]
member this.TestSquare() =
Assert.AreEqual(
0, MathHelper.square(0.0))
Assert.AreEqual(
4, MathHelper.square(2.0))

[<Test
>]
member this.TestGeneratePrimes() =
let primesLessThan2 = MathHelper.generatePrimes(1)
CollectionAssert.IsEmpty(primesLessThan2)

let primesNotGreaterThan2 = MathHelper.generatePrimes(2)
CollectionAssert.IsNotEmpty(primesNotGreaterThan2)
CollectionAssert.Contains(primesNotGreaterThan2,
2)
Assert.AreEqual(
1, primesNotGreaterThan2.Length)

let primesNotGreaterThan10 = MathHelper.generatePrimes(10)
CollectionAssert.IsNotEmpty(primesNotGreaterThan10)
CollectionAssert.Contains(primesNotGreaterThan10,
7)
Assert.AreEqual(
4, primesNotGreaterThan10.Length)

// Other testcases
end
复制代码


这里只编写了对函数square和generatePrimes的测试。如果你在C#中用过NUnit,看这样的代码就没有任何问题了。测试结果为:

使用FsUnit进行单元测试

FsUnit是一个Specification测试框架。它的目标是将单元测试和行为(函数)的规格尽量简化,并以函数式的风格代替命令式风格的测试代码。

Specification可以翻译为规格说明,就是说测试代码实际上是对待测代码的一条条规格说明。比如对函数square,它求一个数的平方,那么一条规格可以是:”square(2) should equal 4”。好了,惊喜就要来了:

复制代码
F# Code - FsUnit tester
#light

open FsUnit
open MyFsLib

let squareSpecs =
specs
"Test square" [
spec
"square(0) should equal 0"
(MathHelper.square(
0.0) |> should equal 0.0) // Pass
spec "square(2) should equal 2"
(MathHelper.square(
2.0) |> should equal 2.0) // Fail
]

let generatePrimes1Specs =
specs
"Test generatePrimes" [
spec
"generatePrimes(1).Length should equal 0"
(MathHelper.generatePrimes(
1).Length |> should equal 0)
]

let generatePrimes2Specs =
specs
"Test generatePrimes" [
spec
"generatePrimes(2).Length should equal 1"
(MathHelper.generatePrimes(
2).Length |> should equal 1)
spec
"generatePrimes(2) should contain 2"
(MathHelper.generatePrimes(
2) |> should contain 2)
]

let generatePrimes10Specs =
specs
"Test generatePrimes" [
spec
"generatePrimes(10).Length should equal 4"
(MathHelper.generatePrimes(
10).Length |> should equal 4)
spec
"generatePrimes(10) should contain 7"
(MathHelper.generatePrimes(
10) |> should contain 7)
spec
"generatePrimes(10) should not contain 9"
(MathHelper.generatePrimes(
10) |> should not' (contain 9))
]

printfn
"%s" (Results.summary())
复制代码


这里没有Assert,有的是should,这两个词给人的感觉可大不一样,而且通过函数的组合,我们可以写出should equal这样的“句子”。这里的测试代码已经比较接近自然语言了。

一条spec就是一条规格说明,它说明待测的函数具有什么样的规格,我们把这些都放在specs中,测试结束后,使用Results.summary函数来显示测试结果:
 
如果对FsUnit感兴趣,可以到http://code.google.com/p/fsunit/这里来看看。感觉目前它还有些欠缺,比如没有像CollectionAssert这样的测试类,接下来看看能不能扩展一下。

小结

本文介绍了在F#中如何使用NUnit和FsUnit进行单元测试。可以看到两者都很简单,前者简单是因为能很好地延续在C#中的方式,迁移过来不要费多大力气;后者简单是因为它接近自然语言,看起来很亲切。FsUnit值得关注,除了单元测试本身,我们还可以通过它来了解Language-Oriented Programming的相关知识。

(要了解本人所写的其它F#随笔请查看 F#系列随笔索引

参考

《Foundations of F#》 by Robert Pickering
http://code.google.com/p/fsunit/


本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2008/11/18/fsharp-adventures-unit-test.html,如需转载请自行联系原作者。

目录
相关文章
|
1月前
|
Java 测试技术 开发者
初学者入门:掌握单元测试的基础与实践
【10月更文挑战第14天】单元测试是一种软件测试方法,它验证软件中的最小可测试单元——通常是单独的函数或类——是否按预期工作。单元测试的目标是确保每个模块在其自身范围内正确无误地运行。这些测试应该独立于其他模块,并且应该能够反复执行而不受外部环境的影响。
54 2
|
3月前
|
测试技术 Go
写出高质量代码的秘诀:Golang中的测试驱动开发(TDD)
写出高质量代码的秘诀:Golang中的测试驱动开发(TDD)
|
3月前
|
测试技术 数据库
探索JSF单元测试秘籍!如何让您的应用更稳固、更高效?揭秘成功背后的测试之道!
【8月更文挑战第31天】在 JavaServer Faces(JSF)应用开发中,确保代码质量和可维护性至关重要。本文详细介绍了如何通过单元测试实现这一目标。首先,阐述了单元测试的重要性及其对应用稳定性的影响;其次,提出了提高 JSF 应用可测试性的设计建议,如避免直接访问外部资源和使用依赖注入;最后,通过一个具体的 `UserBean` 示例,展示了如何利用 JUnit 和 Mockito 框架编写有效的单元测试。通过这些方法,不仅能够确保代码质量,还能提高开发效率和降低维护成本。
53 0
|
3月前
|
测试技术 开发者
守护代码质量的利器:揭秘Vaadin单元测试的奥秘,助你打造无懈可击的Web应用
【8月更文挑战第31天】在软件开发中,单元测试是确保代码质量和稳定性的重要手段。对于使用Vaadin框架开发的Web应用,有效的单元测试尤为关键。Vaadin提供了完善的工具链支持,并鼓励测试驱动开发(TDD)。本文详细介绍了如何为Vaadin应用编写单元测试,并通过具体示例展示了测试环境搭建、依赖配置以及对简单`UserForm`组件的测试方法。通过JUnit和Mockito,我们验证了表单字段的变化及有效性,确保组件按预期工作,从而提升应用的整体健壮性和可靠性。这不仅有助于发现潜在问题,还能简化未来的维护工作。
40 0
|
6月前
|
NoSQL Java 测试技术
谈谈如何使用好单元测试这把武器
本文作者结合我们日常的工作,讨论如何使用好单元测试这把武器。
|
Java 测试技术 Python
关于如何写自动化测试框架,看完本章你会有收获
关于如何写自动化测试框架,看完本章你会有收获
113 0
|
Web App开发 存储 前端开发
前端自动化测试之葵花宝典
前端自动化测试之葵花宝典
|
自然语言处理 Java 测试技术
告别祈祷式编程|单元测试在项目里的正确落地姿势
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Jav...
173 1
|
JSON Java 测试技术
谈一谈单元测试
写在前面对于我们开发人员来说,单元测试一定不会陌生,但在各种原因下会被忽视,尤其是在我接触到的项目中,提测阶段发现各种各样的问题,我觉得有必要聊一下单元测试。对于单元测试到底有没有存在的必要,这里不是我想要说的重点。有兴趣的可以去了解一下:【单元测试和TDD】【单元测试到底是什么】为了写而写的单元测试没什么价值,但一个好的单元测试带来的收益是非常客观的。问题是怎么去写好单元测试?怎么去驱动写好单元
658 0
谈一谈单元测试
|
Java 测试技术 程序员
单元测试经典三问:是什么,为什么,怎么做?
编写合格的单元测试可以说是 Java 程序员的基本功。 很多公司对但单测覆盖率都会有要求,通常要求在 60% 到 90% 不等。 但是很多同学对单元测试或多或少有一些抵触,对如何写出“标准”的单元测试代码存在疑问。 有些同学编写单元测试,纯粹是应付工作,完全起不到单测应该起到的作用。 本文解答单元测试的三个基本问题,即单元测试是什么,为什么编写单元测试,怎么编写单元测试?
837 0
单元测试经典三问:是什么,为什么,怎么做?
下一篇
无影云桌面