如何在xunit中模拟Db连接?

时间:2019-02-18 11:56:33

标签: c# .net-core xunit

我正在xUnit中编写单元测试用例。我正在编写用于打开数据库连接的单元测试用例。当数据库关闭时,我正在写负面案例。

下面是我与数据库建立连接的真实代码。

 public IDbConnection CreateDirectDb2Connection(int attempt = 0)
    {
      try
      {
        var conn = new DB2Connection(BuildDB2ConnectionString());
        conn.Open();
        return conn;
      }
      catch (Exception ex)
      {
        logService.Debug($"Failed to create and open a connection, attempt {attempt + 1}/3, error: {ex}");
        if (attempt < 2)
        {
          // Retry twice
          return CreateDirectDb2Connection(attempt + 1);
        }

        throw ex;
      }
    }   

下面是我的xUnit测试用例代码。

 public class ContextProviderServiceTests
    {
    private readonly IContextProviderService contextProvider = Substitute.For<IContextProviderService>();
    private readonly IDbCommand db2Command;
    private readonly MainframeDirectAccessRepository mainframeRepository;
    private readonly IDbConnection db2Connection;
      public ContextProviderServiceTests()
       {
          db2Connection = Substitute.For<IDbConnection>();
      db2Command = Substitute.For<IDbCommand>();
      db2Command.Parameters.Returns(Substitute.For<IDataParameterCollection>());
      db2Command.CreateParameter().Returns(Substitute.For<IDbDataParameter>());

      commandParameters = new List<TestDataParameter>();
      db2Command.Parameters.When(x => x.Add(Arg.Any<object>()))
        .Do(c => commandParameters.Add(new TestDataParameter
          {
            Name = c.Arg<IDbDataParameter>().ParameterName,
            Value = c.Arg<IDbDataParameter>().Value,
            DbType = c.Arg<IDbDataParameter>().DbType
          }));
     }
    [Fact]
    public void CreateDirectDb2ConnectionFailure()
    {
      var connection = mockProvider.GetDependency<IContextProviderService();
      connection.CreateDirectDb2Connection().Returns("I am not sure what to 
      return here");
    }

有人可以帮我编写负面的单元测试用例(当DB关闭时)吗?任何帮助,将不胜感激。谢谢

1 个答案:

答案 0 :(得分:1)

您应该在Interface Segregation的帮助下使用Dependency Inversion principle来遵守Inversion of ControlDependency Injection

这样,您可以在单元测试中创建一个MockDB2Connection,并将其注入到构造函数中,而在实际代码中,您将传递适当的DB2Connection。

假设您有这样的服务:

public class SomeService
{
    private readonly IDbConnection _dbCOnnection;

    public SomeService(IDbConnection dbConnection)
    {
        _dbCOnnection = dbConnection;
    }

    public async Task<IEnumerable<Foo>> GetFoos()
    {
        // Obviously don't do this in production code;
        // just for demonstration purposes.
        await _dbCOnnection.OpenAsync();
    }
}

您可以像这样实现模拟连接类:

public interface IDbConnection
{
    Task OpenAsync();

    // Other required methods...
}

public class ThrowingDbConnection : IDbConnection
{
    public Task OpenAsync()
    {
        throw new Exception("...");
    }
}

public class FakeDbConnection : IDbConnection
{
    public Task OpenAsync()
    {
        return Task.CompletedTask;
    }
}

作为IoC容器,您有多种选择。微软的Microsoft.Extensions.DependencyInjection,AutoFac,CastleWindsor,Ninject等。选择一个适合您的需求。在大多数情况下,Microsoft或AutoFac在这里应该是不错的选择。