简体   繁体   English

单元测试难题:OleDbCommand

[英]Unit testing conundrum: OleDbCommand

One of the classes which I'm trying to unit test makes use of an OleDbConnection object. 我要进行单元测试的类之一利用了OleDbConnection对象。 This object is responsible for returning information held in an MS Access file based on a passed SQL string. 该对象负责根据传递的SQL字符串返回保存在MS Access文件中的信息。 The code is: 代码是:

public void getInformation(DateTime start, DateTime finish)
{
    string getInfo = "";
    string query = "//Query for MS Access goes here";
    transactions = addTransactions(query, conn);
}

Where addTransactions is a private method that returns the list which was retrieved from the database: 其中addTransactions是一个私有方法,该方法返回从数据库中检索到的列表:

private List<string> addTransactions(string query, OleDbConnection conn)
{
    List<string> returnedData = new List<string>();
    OleDbCommand cmd = new OleDbCommand(query, conn);
    try
    {
        if (conn.State == ConnectionState.Closed) conn.Open();
        OleDbDataReader reader = cmd.ExecuteReader();
        while (reader.Read())
        {
            if (!reader.IsDBNull(0))
        }
        returnedData.Add(reader.GetString(0));
    }
    catch (Exception ex)
    {
        Console.WriteLine("OLEB: {0}", ex.Message);
    }
    conn.Close();
    return returnedData;
}

Now I know already from looking at this method that it's going to be difficult to unit test, since the public getInformation() method is void. 现在,通过查看此方法,我已经知道很难进行单元测试,因为公共的getInformation()方法是无效的。 What I can do is test that the returned data has something in it. 我所能做的就是测试返回的数据是否包含某些内容。 My question is how can I write a unit test involving the OleDbConnection? 我的问题是如何编写涉及OleDbConnection的单元测试?

The only 2 potential solutions I have thought of involve either creating a temp access file (not ideal since we're now outside the scope of unit testing coupled with the potential to fail when the test is run on other developer's machines) or creating a wrapper for OleDbConnection and using that in the unit test (this sounds like the best approach, but I've got no idea where to start on this). 我想到的仅有的两种潜在解决方案包括创建一个临时访问文件(这不理想,因为我们现在不在单元测试范围之内,并且在其他开发人员的机器上运行测试时可能会失败)。为OleDbConnection并在单元测试中使用它(这听起来是最好的方法,但是我不知道从哪里开始)。

or creating a wrapper for OleDbConnection and using that in the unit test 或为OleDbConnection创建包装器,并在单元测试中使用该包装器

That would be my approach. 那就是我的方法。 Objects which aren't directly mockable/testable often represent dependencies in and of themselves. 不直接可模拟/不可测试的对象通常表示自身的依赖关系。 And all dependencies should be provided rather than internally instantiated. 并且应该提供所有依赖关系,而不是内部实例化。

A wrapper can be a simple pass-through which provides the identical functionality. 包装器可以是提供相同功能的简单传递。 Have it be driven by an interface and code to that interface, so you can provide mocks for that interface for unit testing. 由接口驱动该接口并编写该接口的代码,以便为该接口提供模拟以进行单元测试。 (As an added bonus, your mocks give you something to observe even when the method being tested returns void . So you don't have to drill too deep into the system that you're testing, just observe what gets called on the mocks.) (作为一项额外的奖励,即使正在测试的方法返回void ,您的模拟也可以让您观察到一些东西。因此,您不必深入测试的系统,只需观察一下模拟调用的内容即可。 )

Starting at the aggregate root of what you're mocking, you need to wrap the OleDbConnection . 从要模拟的内容的总根开始,需要包装OleDbConnection A simple example to get started might look like this: 一个简单的入门示例可能如下所示:

public interface IDbConnection
{
    IDbCommand CreateCommand();
    // other methods
}

public class MyOleDbConnection : IDbConnection
{
    private OleDbConnection conn;

    public MyOleDbConnection()
    {
        // initialize "conn" here
    }

    public IDbCommand CreateCommand()
    {
        return conn.CreateCommand();
    }

    // other pass-thru methods
}

Essentially it's just a pass-through wrapper for identical functionality exposed by the underlying object(s). 本质上,它只是底层对象公开的相同功能的直通包装。 The benefit there is that this object doesn't really need to be unit-tested, because it doesn't contain any meaningfully testable logic. 这样做的好处是, 对象实际上不需要进行单元测试,因为它不包含任何有意义的可测试逻辑。 (Sure, it would be nice to get to 100%, but the return on investment just isn't there with this class.) (当然,达到100%会很好,但是此类投资并不具备投资回报率。)

As you can see, this also involves creating a wrapper for OleDbCommand in a similar manner. 如您所见,这还涉及以类似方式为OleDbCommand创建包装器。 Again, just pass-through methods. 同样,只是传递方法。

Once you have your dependencies wrapped and mockable, you'd change your class to use the wrappers. 一旦您的依赖项被包装并且是可模拟的,就可以更改类以使用包装器。 For example, instead of this: 例如,代替此:

OleDbCommand cmd = new OleDbCommand(query, conn);

Which internally holds a reference to the dependency, you'd do this: 内部保留对依赖项的引用,您可以这样做:

IDbCommand cmd = conn.CreateCommand();

Which asks the dependency for a reference to something. 要求依赖项引用某些东西。 This puts the responsibility of maintaining the dependency on the dependency itself, rather than in this class you're trying to test. 这就将维护依赖关系的责任放在依赖关系本身上,而不是在您要测试的此类中。 (And, in doing so, trying to keep free to dependencies.) (并且在这样做时,尝试保持对依赖关系的自由。)

Once the dependencies are fully removed from your class, you're free to mock and test all you like. 一旦从类中完全删除了依赖项,您就可以随意模拟和测试所有您喜欢的东西。

Just create an MS file and place in package then always use same file to test that way you can even write the data and know exactly what its returning instead of assuming if any data is returned its correct! 只需创建一个MS文件并放入包装中,然后始终使用同一文件来测试该方式,您甚至可以写入数据并确切知道其返回的内容,而不用假设是否已返回任何正确的数据! Just an idea multiple ways to go about it. 只是一个想法,有多种解决方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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