解剖SQLSERVER 第六篇 对OrcaMDF的系统测试里避免regressions (译)
http://improve.dk/avoiding-regressions-in-orcamdf-by-system-testing/
当我继续添加新功能和新的数据结构支持进去OrcaMDF软件的时候, bug的风险 不断增加
特别是当我开发一个很大的未知功能时,我不能预估结构和该结构的关联,为了降低风险,测试是很有必要的
单元测试
单元测试 是在面向对象编程里测试源代码某一个功能的最小一部分的测试。一个测试的例子是 SqlBigInt数据类型 解析类,
他应该长这个样子
using
System;
using
NUnit.Framework;
using
OrcaMDF.Core.Engine.SqlTypes;
namespace
OrcaMDF.Core.Tests.Engine.SqlTypes
{
[TestFixture]
public
class
SqlBigIntTests
{
[Test]
public
void
GetValue()
{
var
type =
new
SqlBigInt();
byte
[] input;
input
=
new
byte
[] {
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0x7F
};
Assert.AreEqual(
9223372036854775807
, Convert.ToInt64(type.GetValue(input)));
input
=
new
byte
[] {
0x82
,
0x5A
,
0x03
,
0x1B
,
0xD5
,
0x3E
,
0xCD
,
0x71
};
Assert.AreEqual(
8200279581513702018
, Convert.ToInt64(type.GetValue(input)));
input
=
new
byte
[] {
0x7F
,
0xA5
,
0xFC
,
0xE4
,
0x2A
,
0xC1
,
0x32
,
0x8E
};
Assert.AreEqual(
-
8200279581513702017
, Convert.ToInt64(type.GetValue(input)));
}
[Test]
public
void
Length()
{
var
type =
new
SqlBigInt();
Assert.Throws
<ArgumentException>(() => type.GetValue(
new
byte
[
9
]));
Assert.Throws
<ArgumentException>(() => type.GetValue(
new
byte
[
7
]));
}
}
}
这个测试包含了SqlBigInt 类的主入口点,测试long bigint 数据类型是否会造成上溢或下溢的情况,也包含长度检查。
对于像SqlBigInt这样简单的类型单元测试会工作得很好。有时候单元测试会很复杂当相关联的类需要调用相应方法,类等支持他运行的底层结构的时候( mock测试 )
虽然这是一个工作策略,测试需要不断进行,特别在项目早期阶段,整个架构都是动态的
系统测试
在测试范围上,我们需要更大的范围测试 -系统测试。系统测试旨在测试系统作为一个整体,基本上忽略系统内部工作原理
如果要分类的话可以被分为 黑盒测试。对于OrcaMDF,我估计可以捕获90%的所有的regressions 只使用10%的时间,
相比起单元测试使用更多时间只捕获少量的regressions 。
因此,这是一个很好的方法在开发期间的测试,同时可以引入关键的单元测试和集成测试。
例如我想测试DatabaseMetaData 类里面的用户表名字的解析,我可以模拟SysObjects的值列表,同时对于DatabaseMetaData 类
的构造函数也能模拟MdfFile 所必须的参数,为了做到这一点,我必须从MdfFile 提取出一个接口并且在上面使用mocking framework
系统测试的方法执行以下流程:
1、连接到SQLSERVER实例
2、在 测试固件(Test fixture) 里创建测试架构
3、分离数据库
4、运行OrcaMDF 并加载分离的数据库验证结果
一个测试样例,创建两个用户表并且验证DatabaseMetaData类的输出
using
System.Data.SqlClient;
using
NUnit.Framework;
using
OrcaMDF.Core.Engine;
namespace
OrcaMDF.Core.Tests.Integration
{
public
class
ParseUserTableNames : SqlServerSystemTest
{
[Test]
public
void
ParseTableNames()
{
using
(
var
mdf =
new
MdfFile(MdfPath))
{
var
metaData =
mdf.GetMetaData();
Assert.AreEqual(
2
, metaData.UserTableNames.Length);
Assert.AreEqual(
"
MyTable
"
, metaData.UserTableNames[
0
]);
Assert.AreEqual(
"
XYZ
"
, metaData.UserTableNames[
1
]);
}
}
protected
override
void
RunSetupQueries(SqlConnection conn)
{
var
cmd =
new
SqlCommand(
@"
CREATE TABLE MyTable (ID int);
CREATE TABLE XYZ (ID int);
"
, conn);
cmd.ExecuteNonQuery();
}
}
}
在实际的真实生活场景里这样可以非常快速的进行测试。想测试转发记录的解析?只需要简单地创建一个新的测试
编写TSQL代码来生成目标数据库状态然后验证扫描到的表数据
系统测试的缺点
不幸的是系统测试不是万能药,它也有它的缺点。最明显的一个缺点是性能。
单元测试通常需要运行非常快,基本上允许您在每个文件保存后在后台运行它们。从绑定CPU开始到运行 ,每一个这样的系统测试都需要半秒
幸运的是,它们可以并行运行没有问题。在一台四核的机器能让我每分钟运行480个测试。这能够让一个完整的测试集合控制在合理的时间,
同时依然保持测试子集能够很快运行。通常代码的更改不会对测试造成太多的影响
第六篇完

