单元测试通过或失败结果不一致
我的一个单元测试在运行时似乎随机通过或失败。对于我来说,为什么会发生这种情况唯一有意义的是,如果每次运行测试时数据库中的数据都进入不同的状态,但我在每次测试中使用事务回滚数据库 - 除非它无法正常工作。这是我的基本单元测试类和有问题的单元测试类。你能看到我可能缺少的东西或者我还应该寻找什么吗?
TestDriven.Net 和 Visual Studio 单元测试框架会发生这种情况。
Partial Public MustInherit Class TestBase
Private _scope As Transactions.TransactionScope
<DebuggerStepThrough()> _
<TestInitialize()> _
Public Sub Setup()
//'Start the Distribution Transaction Coordinator, if it's not already running.
Using dtcService As New System.ServiceProcess.ServiceController("Distributed Transaction Coordinator", My.Computer.Name)
If dtcService.Status = ServiceProcess.ServiceControllerStatus.Stopped Then
dtcService.Start()
End If
End Using
_scope = New TransactionScope(TransactionScopeOption.RequiresNew, New TimeSpan(0))
End Sub
<DebuggerStepThrough()> _
<TestCleanup()>
Public Sub Teardown()
If _scope IsNot Nothing Then
_scope.Dispose()
End If
End Sub
<System.Diagnostics.DebuggerStepThrough()> _
Public Shared Function ExecSql(ByVal sql As String) As System.Data.DataTable
Dim connStr = GlobalSettings.GetConnectionString()
Using conn As New System.Data.SqlClient.SqlConnection(connStr)
conn.Open()
Dim cmd As New System.Data.SqlClient.SqlCommand(sql.ToString, conn)
Dim adapter As System.Data.SqlClient.SqlDataAdapter = New System.Data.SqlClient.SqlDataAdapter(cmd)
Dim dt As System.Data.DataTable = New System.Data.DataTable
adapter.Fill(dt)
Return dt
If conn.State <> System.Data.ConnectionState.Closed Then
conn.Close()
End If
conn.Dispose()
End Using
End Function
End Class
这是我的单元测试:
Partial Public Class CampaignEmailSendLimitServiceTests
Inherits TestBase
Private _service = ServiceManager.Current.MyService
<TestMethod()> _
Public Sub MyTest()
//' Set the pre-test condition.
ExecSql("update base.dbo.tblTableA set someDate = '2010-06-28' where id = 56937 ")
//' Run the service
_service.Process()
//' Verify the expected result
Dim dt = ExecSql("select deliveryDate from tblTableB ")
Assert.AreEqual(False, dt.Rows(0).IsNull("deliveryDate"))
End Sub
End Class
One of my unit tests seems to randomly pass or fail when I run it. The only thing that makes sense to me for why this is happening is if the data in the database is getting into a different state each time the test is ran, but I use transactions to rollback the database in each test - unless it's not working right. Here's my base unit test class and the unit test class that's having the problem. Can you see anything I might be missing or what else I should look for?
This happens with TestDriven.Net and the Visual Studio Unit Test Framework.
Partial Public MustInherit Class TestBase
Private _scope As Transactions.TransactionScope
<DebuggerStepThrough()> _
<TestInitialize()> _
Public Sub Setup()
//'Start the Distribution Transaction Coordinator, if it's not already running.
Using dtcService As New System.ServiceProcess.ServiceController("Distributed Transaction Coordinator", My.Computer.Name)
If dtcService.Status = ServiceProcess.ServiceControllerStatus.Stopped Then
dtcService.Start()
End If
End Using
_scope = New TransactionScope(TransactionScopeOption.RequiresNew, New TimeSpan(0))
End Sub
<DebuggerStepThrough()> _
<TestCleanup()>
Public Sub Teardown()
If _scope IsNot Nothing Then
_scope.Dispose()
End If
End Sub
<System.Diagnostics.DebuggerStepThrough()> _
Public Shared Function ExecSql(ByVal sql As String) As System.Data.DataTable
Dim connStr = GlobalSettings.GetConnectionString()
Using conn As New System.Data.SqlClient.SqlConnection(connStr)
conn.Open()
Dim cmd As New System.Data.SqlClient.SqlCommand(sql.ToString, conn)
Dim adapter As System.Data.SqlClient.SqlDataAdapter = New System.Data.SqlClient.SqlDataAdapter(cmd)
Dim dt As System.Data.DataTable = New System.Data.DataTable
adapter.Fill(dt)
Return dt
If conn.State <> System.Data.ConnectionState.Closed Then
conn.Close()
End If
conn.Dispose()
End Using
End Function
End Class
And here's my unit test:
Partial Public Class CampaignEmailSendLimitServiceTests
Inherits TestBase
Private _service = ServiceManager.Current.MyService
<TestMethod()> _
Public Sub MyTest()
//' Set the pre-test condition.
ExecSql("update base.dbo.tblTableA set someDate = '2010-06-28' where id = 56937 ")
//' Run the service
_service.Process()
//' Verify the expected result
Dim dt = ExecSql("select deliveryDate from tblTableB ")
Assert.AreEqual(False, dt.Rows(0).IsNull("deliveryDate"))
End Sub
End Class
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这对我来说一直很有效。我看到的主要区别是使用 TransactionScopeOption.Required。
This has always worked for fine for me. The main difference I see is using TransactionScopeOption.Required.
为什么使用 DataAdapter.Fill 来执行更新?它旨在用 select 语句填充 DataTables。
我的猜测是,您首先没有使用 ExecSql 向数据库写入任何内容。
第二件事。该断言尽可能不可读。
我会改为
或
不可读
的测试是有些人说单元测试不好的原因之一,因为它会减慢你的速度。您必须使单元测试尽可能易于阅读和理解。这样他们就不会反对单元测试;)
可能会有一些拼写错误,因为我不使用 VB.NET。断言示例来自 NUnit。
Why are You using DataAdapter.Fill to execute updates? It is designed to fill DataTables with select statements.
My guess is that You didn't write anything to database using ExecSql in the first place.
And second thing. That assert is as unreadable as possible.
I would change
to
or
Unreadable tests are one of the reasons some people say Unit Testing is bad because it slows You down. You have to make Unit Tests as easy to read and understand as possible. So that they don't have arguments against unit testing ;)
There may be some typos as I don't use VB.NET. Assert examples are from NUnit.
我终于明白是怎么回事了。这与交易无关。这一切都很好。我的流程故意造成了不一致的行为。如果没有找到其他排名,该过程的一部分有一个“随机排名”来确定交货日期。单元测试需要重写以更好地反映业务规则。
I finally figured out what was going on. It had nothing to do with transactions. That's all working great. It was my process that was creating inconsistent behavior - by design. There was a part of the process that had a "random ranking" to determine the deliveryDate if no other rankings where found. The unit test needs to be rewritten to better reflect the business rules.