'Dynamically mock properties for unit testing
So, I have built a "db context" like EF but for MongoDb, instead of DbSets I have some properties of type IMongoCollection<>. My problem is testing that all properties return the correct collection, for the exception I iterate every property that I found with reflection and I call it, but when I try to mock with moq the IMongoDatabase that returns the IMongoCollection<> I always have this exception
System.NotSupportedException: Unsupported expression: ... => ....Invoke(db, new[] { It.Is(s => s == type.Name), It.Is...
System.NotSupportedException Unsupported expression: ... => ....Invoke(db, new[] { It.Is(s => s == type.Name), It.Is(s => s == null) }) Non-overridable members (here: MethodBase.Invoke) may not be used in setup / verification expressions. at Moq.Guard.IsOverridable(MethodInfo method, Expression expression) in C:\projects\moq4\src\Moq\Guard.cs:line 99
My code
public class GufoDbContextTests : IDisposable
{
private readonly GufoDbContext _dbContext;
private readonly Mock<IMongoClient> _mongoClientMock;
private readonly PropertyInfo[] _collections;
public GufoDbContextTests()
{
_collections = typeof(GufoDbContext).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead)
.Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(IMongoCollection<>))
.ToArray();
_mongoClientMock = new Mock<IMongoClient>();
_dbContext = new GufoDbContext(_mongoClientMock.Object);
}
[Fact]
public void AllCollections_Success_WhenDatabaseIsConnected()
{
var mongoDatabaseMock = new Mock<IMongoDatabase>();
_mongoClientMock.Setup(client =>
client.GetDatabase(It.Is<string>(c => c == DatabaseConsts.Database),
It.IsAny<MongoDatabaseSettings>()))
.Returns(mongoDatabaseMock.Object);
foreach (var collection in _collections)
{
var type = collection.PropertyType.GetGenericArguments().First();
var returnType =
(Mock)Activator.CreateInstance(
typeof(Mock<>).MakeGenericType(
typeof(IMongoCollection<>).MakeGenericType(type)
)
)!;
mongoDatabaseMock.Setup(db =>
db.GetType()
.GetMethod(nameof(IMongoDatabase.GetCollection))!
.MakeGenericMethod(type)
.Invoke(db, new object[]
{
It.Is<string>(s => s == type.Name),
It.Is<MongoCollectionSettings>(s => s == null)
})
)
.Returns(returnType.Object);
}
_dbContext.OpenConnection(Guid.NewGuid().ToString());
foreach (var collection in _collections)
{
Assert.NotNull(collection.GetValue(_dbContext, null));
}
foreach (var collection in _collections)
{
var type = collection.PropertyType.GetGenericArguments().First();
mongoDatabaseMock.Verify(db =>
db.GetType()
.GetMethod(nameof(db.GetCollection))!
.MakeGenericMethod(type)
.Invoke(db, new object[]
{
It.Is<string>(s => s == type.Name),
It.IsAny<MongoCollectionSettings>()
}),
Times.Once
);
}
_mongoClientMock.Verify(client =>
client.GetDatabase(It.Is<string>(c => c == DatabaseConsts.Database),
It.IsAny<MongoDatabaseSettings>()),
Times.Once);
mongoDatabaseMock.VerifyNoOtherCalls();
}
/// <inheritdoc />
public void Dispose()
{
GC.SuppressFinalize(this);
_mongoClientMock.VerifyNoOtherCalls();
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
