单元测试不一致的通过或失败结果

时间:2011-05-16 18:05:29

标签: vb.net visual-studio-2010 unit-testing transactions testdriven.net

当我运行它时,我的一个单元测试似乎随机传递或失败。对我来说唯一有意义的原因是每次运行测试时数据库中的数据是否进入不同的状态,但我在每次测试中使用事务来回滚数据库 - 除非它不能正常工作。这是我的基本单元测试类和有问题的单元测试类。你能看到我可能遗失的任何东西或我应该寻找的其他东西吗?

使用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

3 个答案:

答案 0 :(得分:1)

这对我来说一直很好。我看到的主要区别是使用TransactionScopeOption.Required。

[TestClass()]
public class MyTest: DatabaseTestClass
{

    public MyTest()
    {
        InitializeComponent();
    }

    TransactionScope ambientTransaction;

    [TestInitialize()]
    public void TestInitialize()
    {
        ambientTransaction = new TransactionScope(TransactionScopeOption.Required);
        base.InitializeTest();
    }

    [TestCleanup()]
    public void TestCleanup()
    {
        ambientTransaction.Dispose();
        base.CleanupTest();
    }
}

答案 1 :(得分:0)

为什么使用DataAdapter.Fill执行更新?它旨在用select语句填充DataTables。

我的猜测是你首先没有使用ExecSql向数据库写任何内容。

第二件事。该断言尽可能不可读。 我会改变

Assert.AreEqual(False, dt.Rows(0).IsNull("deliveryDate"));

Assert.IsFalse(dt.Rows(0).IsNull("deliveryDate"));

Assert.That(dt.Rows(0)("deliveryDate"), Is.Not.Null));

不可读的测试是一些人说单位测试很糟糕的原因之一,因为它减慢了你的速度。您必须使单元测试尽可能易于阅读和理解。这样他们就没有反对单元测试的论据;)

由于我不使用VB.NET,可能会有一些拼写错误。断言示例来自NUnit。

答案 2 :(得分:0)

我终于弄清楚发生了什么。它与交易无关。这一切都很有效。正是我的过程创造了不一致的行为 - 按设计。如果找不到其他排名,则该过程的一部分具有“随机排名”以确定deliveryDate。需要重写单元测试以更好地反映业务规则。