Open darthmolen opened 5 years ago
Try this:
var mock = new Mock<DbConnection>();
mock.As<IDbConnection>()
.Setup(x => x.BeginTransaction())
.Returns(() => new Mock<DbTransaction>().Object);
var connection = (IDbConnection)mock.Object;
using (var transaction = connection.BeginTransaction())
{
transaction.Commit();
}
Best I understand, this is because DbConnection
doesn't let you override BeginTransaction
but you can with a new implementation of IDbConnection
for the mock, you just have to remember to cast the mocked object to IDbConnection
otherwise it will try to use the DbConnection.BeginTransaction
method which won't work because the protected method isn't implemented as Moq returns default for abstract methods, e.g. default(DbTransaction) == null
.
Thanks @smokedlinq for explaining that.
@smokedlinq you were able to do this in a functional way? I tried many solutions and found yours but my mock threw on SQL mapper when assigned the transaction mock to the command.
var mock = new Mock<DbConnection>();
mock.As<IDbConnection>()
.Setup(x => x.BeginTransaction())
.Returns(()=> transactionMock.Object);
var connection =(IDbConnection)mock.Object;
mock.SetupDapperAsync(c => c.ExecuteAsync(It.IsAny<string>(), null, null, null, null))
.ReturnsAsync(0);
_connectionFactoryMock.Setup(e => e.CreateConnectionOpened()).Returns(connection);
In my scenario, we have to have this connection factory returning a connection (company policy).
Does the SetupDapperAsync not take a transaction then? Did you try doing the setup before you generated a proxy on mock.Object?
For your first question I think so, and the second one yes it was my first attempt.
Here is a quick example I put together ... is this close to what you are testing ... it's working on my sample app ...
using Dapper;
using FluentAssertions;
using Moq;
using Moq.Dapper;
using System.Data;
using System.Data.Common;
using System.Threading.Tasks;
var transactionMock = new Mock<DbTransaction>();
var connectionFactoryMock = new Mock<IConnectionFactory>();
var mock = new Mock<DbConnection>();
mock.As<IDbConnection>()
.Setup(x => x.BeginTransaction())
.Returns(() => transactionMock.Object);
mock.SetupDapperAsync(c => c.ExecuteAsync(It.IsAny<string>(), It.IsAny<IDbTransaction>(), null, null, null))
.ReturnsAsync(0);
var connection = (IDbConnection)mock.Object;
connectionFactoryMock.Setup(e => e.CreateConnectionOpened()).Returns(connection);
var result = await ExecuteQueryAsync(connectionFactoryMock.Object);
result.Should().Be(0);
async Task<int> ExecuteQueryAsync(IConnectionFactory factory)
{
using var connection = factory.CreateConnectionOpened();
using var transaction = connection.BeginTransaction();
var result = await connection.ExecuteAsync("INSERT INTO FU VALUES (1)", transaction: transaction);
transaction.Commit();
return result;
}
public interface IConnectionFactory
{
IDbConnection CreateConnectionOpened();
}
hey @smokedlinq i had to travel and didn't tested until today sorry for the late response, but worked like a charm thank you so much!
When trying to moq with moq.dapper using an IDbTransaction, It seems to call but won't return the "returns".
Using the same call, I pass a null to the setup and the actual call, the returns works.