简体   繁体   中英

Unit Testing class which communicates with a database

Ok Lets assume i have a class which controls my data layer and a class which performs the work.

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;
    }
}

How can i test my DoWork method with a unit test without accessing the database.

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

Make the MyData class a dependency parameter and inject it during construction of your MyWork class. For unit testing purposes, mock the dependency in your unit test to ensure that it is calling the defined dependency's contract in an expected manner.

Typically this means:

  • Defining an interface for the dependency ie IMyData
  • The constructor signature should expect the interface type rather than the concrete type.

As a final result, your code would be transformed as follows:

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;
    }
}

As a step further, you should check out the SOLID design principles as this type of design demonstrates why they exist.

More on Wikipedia: SOLID (OO design)

Edit:

Your unit test would then look something like (assuming you're using the Moq mocking framework):

[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);
}

..but in the real world you would more than likely instantiate MyWork with a real MyData instance as follows (unless you're using a Dependency Injection framework such as MEF or Unity):

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

First, follow @toadflakz advice and inject MyData to MyWork 's constructor.

Then, use some ORM to map the data from the db to objects. Don't use DataTable .

To make DoWork easier to test, consider refactoring it into a pure function :

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

This way the result of DoWork depends only on the input parameter, which makes it very easy to test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM