与数据库通信的单元测试类

时间:2015-10-14 15:34:59

标签: c# database unit-testing

Ok让我们假设我有一个控制我的数据层的类和一个执行工作的类。

class MyData
{
    public DataTable GetMyData()
    {
         return Query.MyDataBase.ResultDT();
    }
}

class MyWork
{
    public int DoWork()
    {
        MyData Data = new MyData();
        DataTable DT = Data.GetMyData();
        return DT.Rows.Count;
    }
}

如何在不访问数据库的情况下使用单元测试来测试我的DoWork方法。

[TestMethod()]
public void TestMyWork()
{
    MyWork work = new MyWork();
    int result = work.DoWork();
    Assert.AreEqual(1, result);
}

2 个答案:

答案 0 :(得分:5)

使MyData类成为依赖项参数,并在构建MyWork类时注入它。出于单元测试的目的,模拟单元测试中的依赖关系,以确保它以预期的方式调用已定义的依赖项合同。

通常这意味着:

  • 定义依赖关系的接口,即IMyData
  • 构造函数签名应该是接口类型而不是具体类型。

作为最终结果,您的代码将转换如下:

interface IMyData
{
    DataTable GetMyData();
}

class MyData : IMyData
{
    public DataTable GetMyData()
    {
         return Query.MyDataBase.ResultDT();
    }
}

class MyWork
{
    private IMyData _myData;

    public MyWork(IMyData myData)
    {
        _myData = myData;
    }

    public int DoWork()
    {
        DataTable DT = _myData.GetMyData();
        return DT.Rows.Count;
    }
}

更进一步,您应该查看SOLID设计原则,因为此类设计说明了它们存在的原因。

更多关于Wikipedia: SOLID (OO design)

修改

您的单元测试看起来就像(假设您正在使用Moq模拟框架):

[TestMethod()]
public void TestMyWork()
{
    var mockMyData = Mock<IMyData>();
    mockMyData.Setup(x => x.GetMyData()).Returns(new DataTable());

    MyWork work = new MyWork(mockMyData);
    int result = work.DoWork();
    Assert.AreEqual(1, result);
}

..但在现实世界中,您很可能使用真实MyWork实例实例化MyData,如下所示(除非您使用的是依赖注入框架,如MEF或Unity): / p>

var myWork = new MyWork(new MyData());

答案 1 :(得分:1)

首先,关注@toadflakz建议并将MyData注入MyWork的构造函数。

然后,使用一些ORM将数据从db映射到对象。请勿使用DataTable

要使DoWork更容易测试,请考虑将其重构为pure function

public int DoWork(DataTable dt)
{
    // make some complex calculations on dt
}

这样DoWork的结果仅取决于输入参数,这使得测试变得非常容易。