Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1078025
  • 博文数量: 403
  • 博客积分: 10272
  • 博客等级: 上将
  • 技术积分: 4407
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:22
文章分类

全部博文(403)

文章存档

2012年(403)

分类: 嵌入式

2012-03-15 21:33:56

我们没有使用TDD,所以单元测试最麻烦的就是准备测试的基础数据。我们现在是使用内存仓储来做单元测试,要为每个仓储都构造基础数据,非常麻烦。

前几天看xunit的源码,看到AutoRollbackAttribute这个特性,异常的兴奋 ^_^。怎么就忘了用事务的自动回滚呢?

我们看AutorollbackAttribute的具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class AutoRollbackAttribute : BeforeAfterTestAttribute
{
IsolationLevel isolationLevel = IsolationLevel.Unspecified;
TransactionScope scope;
TransactionScopeOption scopeOption = TransactionScopeOption.Required;
long timeoutInMS = -1;
///
/// Gets or sets the isolation level of the transaction.
/// Default value is .Unspecified.
///
public IsolationLevel IsolationLevel
{
get { return isolationLevel; }
set { isolationLevel = value; }
}
///
/// Gets or sets the scope option for the transaction.
/// Default value is .Required.
///
public TransactionScopeOption ScopeOption
{
get { return scopeOption; }
set { scopeOption = value; }
}
///
/// Gets or sets the timeout of the transaction, in milliseconds.
/// By default, the transaction will not timeout.
///
public long TimeoutInMS
{
get { return timeoutInMS; }
set { timeoutInMS = value; }
}
///
/// Rolls back the transaction.
///
public override void After(MethodInfo methodUnderTest)
{
scope.Dispose();
}
///
/// Creates the transaction.
///
public override void Before(MethodInfo methodUnderTest)
{
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = isolationLevel;
if (timeoutInMS > 0)
options.Timeout = new TimeSpan(timeoutInMS * 10);
scope = new TransactionScope(scopeOption, options);
}
}

这里使用了.Net Framework自带的TransactionScope。TransactionScope在.NET 2.0中就已经有了,可用于分布式事务。用这种方法来做数据的自动回滚也有一些不足:

  1. 数据库要支持事务。
  2. 内部数据库操作的逻辑里没有事务的实现。

很庆幸的是我们的项目正好都满足上面的2点,唯一不足的就是mongodb不支持事务。所以就需要混合仓储实现了,事务数据库使用真实的仓储,mongodb使用内存仓储。

项目中是用VS自带的单元测试框架,也不想因为这一个特性而改用xunit,那就只能动手把这个迁移到VS的单元测试框架里了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
///
/// 单元测试基类
///
[TestClass]
public class BaseUnitTest
{
IsolationLevel _isolationLevel = IsolationLevel.Unspecified;
TransactionScopeOption _scopeOption = TransactionScopeOption.Required;
TransactionScope _transactionScope;
bool _openAutoRollback = true;
///
/// 构造函数
///
/// 是否开启自动回滚,默认开启
public BaseUnitTest(bool autoRollback = true)
{
_openAutoRollback = autoRollback;
}
///
/// 自动回滚事务初始化
///
[TestInitialize]
public void AutoRollbackBefore()
{
if (_openAutoRollback)
{
var options = new TransactionOptions();
options.IsolationLevel = _isolationLevel;
options.Timeout = new TimeSpan(0, 1, 0);
_transactionScope = new TransactionScope(_scopeOption, options);
}
}
///
/// 自动回滚事务回滚并释放对象
///
[TestCleanup]
public void AutoRollbackAfter()
{
if (_openAutoRollback)
{
if (_transactionScope == null)
throw new InvalidOperationException("未初始化TransactionScope");
//回滚事务
_transactionScope.Dispose();
//释放事务对象
_transactionScope = null;
//移除所有的缓存
RemoveHttpRuntimeCache();
}
}
///
/// 移除所有的HttpRuntime缓存
///
[DebuggerStepThrough]
private void RemoveHttpRuntimeCache()
{
var cache = HttpRuntime.Cache.GetEnumerator();
var keys = new List();
while (cache.MoveNext())
{
keys.Add(cache.Key.ToString());
}
foreach (var key in keys)
{
HttpRuntime.Cache.Remove(key);
}
}
///
/// 设置不自动回滚事务
///
protected void SetAutoRollbackIsUnavailabled()
{
_openAutoRollback = false;
}
}

上面的RemoveHttpRuntimeCache是因为我们在项目中有使用HttpRuntime缓存,关系数据库中的数据回滚后会导致缓存和数据库不一致,所以一但有开启事务的自动回滚,也要相应的清空内存缓存。

阅读(1208) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

重庆贵妃酸辣粉2012-03-16 17:45:32

面馆 特色面馆 百年好面馆5.0黄金版赚钱更轻松
http://suanlamian88.com/a/suanlamian/35.html
酸辣粉嫁富二代不如嫁潜力股 嫁潜力股不如自己做潜力股
http://www.suanlaf.com/a/suanlafentianxiazatan/2011/0815/139.html