我如何模拟 sqlconnection 还是应该重构代码? [英] how do I mock sqlconnection or should I refactor the code?

查看:11
本文介绍了我如何模拟 sqlconnection 还是应该重构代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的代码,我已阅读 Moq 和 SqlConnection?如何存根 IDBconnection,但我仍然不知道如何模拟以下 sqlconnection.

I have the code below, I have read Moq and SqlConnection? and How can I stub IDBconnection, but I still have no idea how to mock the following sqlconnection.

public class SqlBulkWriter : ISqlBulkWriter
{
    private readonly string _dbConnectionString;;

    public SqlBulkWriter(string dbConnectionString)
    {
        this._dbConnectionString = dbConnectionString;
    }

    public void EmptyTable(string schema, string tableName)
    {
        using (var connection = new SqlConnection(this._dbConnectionString))
        {
            try
            {
                connection.Open();
                using (var truncate = new SqlCommand($"TRUNCATE TABLE [{schema}].[{tableName}] ", connection))
                {
                    truncate.ExecuteNonQuery();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex);
            }
            finally
            {
                connection.Close();
            }
        }
    }
}

我要对 EmptyTable 进行单元测试,我想我应该先模拟 sqlconnection 吗?或者我该如何对 EmptyTempTable 进行单元测试?

I'm going to do the unit test for EmptyTable, I think I should mock the sqlconnection firstly? or how do I do the unit test for the EmptyTempTable?

谢谢!许多人欣赏!

推荐答案

SqlBulkWriter 类与实现问题紧密耦合,这使得单独测试该类变得困难.

SqlBulkWriter class is tightly coupled to implementation concerns which make it difficult to test the class in isolation.

知道连接字符串并不是该类真正关心的问题,可以委托给另一个服务.

Knowing the connection string is not really a concern of that class and can be delegated out to another service.

有点像

public interface IDbConnectionFactory {
   IDbConnection CreateConnection();
}

你的类的实现看起来像这样

and its implementation for your class would look something like this

public class SqlConnectionFactory : IDbConnectionFactory {
    private readonly string dbConnectionString;

    public SqlConnectionFactory(string dbConnectionString) {
        this.dbConnectionString = dbConnectionString;
    }

    public IDbConnection CreateConnection() {
        return new SqlConnection(this.dbConnectionString);
    }
}

SqlBulkWriter 类现在可以重构为依赖于抽象而不是具体化.

SqlBulkWriter class can now be refactored to depend on the abstraction instead of the concretion.

public class SqlBulkWriter : ISqlBulkWriter {
    private readonly IDbConnectionFactory connectionFactory;

    public SqlBulkWriter(IDbConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }

    public void EmptyTable(string schema, string tableName) {
        using (var connection = connectionFactory.CreateConnection()) {
            try {
                connection.Open();
                using (var command = connection.CreateCommand()) {
                    command.CommandText = $"TRUNCATE TABLE [{schema}].[{tableName}] ";
                    command.CommandType = CommandType.Text;
                    int rowsAffected = command.ExecuteNonQuery();
                }
            } catch (Exception ex) {
                throw ex;
            } finally {
                connection.Close();
            }
        }
    }
}

这使得类更容易被隔离测试,因为这些抽象可以被模拟并注入到类中.

This allows the class to easier to be tested in isolation as those abstractions can be mocked and injected into the class.

[TestClass]
public class SqlBulkWriter_Should {
    [TestMethod]
    public void EmptyTable() {
        //Arrange
        var mock = new MockRepository(MockBehavior.Default);
        var command = mock.OneOf<IDbCommand>();
        var connection = mock.OneOf<IDbConnection>(_ => _.CreateCommand() == command);
        var factory = mock.OneOf<IDbConnectionFactory>(_ => _.CreateConnection() == connection);

        var subject = new SqlBulkWriter(factory);
        var schema = "dbo";
        var tableName = "TestTable";

        //Act
        subject.EmptyTable(schema, tableName);

        //Assert
        Mock.Get(command).Verify(_ => _.ExecuteNonQuery(), Times.Once());
    }
}

参考 Moq Quickstart 以更好地了解如何使用该框架.

Reference Moq Quickstart to get a better understanding of how to use the framework.

这篇关于我如何模拟 sqlconnection 还是应该重构代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆