I'm learning to use AutoFixture and try to improve my unit tests. I want to modify one of my tests to use AutoData attribute and get mocks from method parameters.
Here is my unit test (it is currently passing):
[Theory, AutoData]
public async Task UpdateMetadata_PassesAllMessagesToSummaryGenerator(ConversationHistory history)
{
// Arrange
var conversationStorage = _fixture.Freeze<Mock<IConversationStorage>>();
var summaryGeneratorMock = _fixture.Freeze<Mock<ISummariesMetadataGenerator>>();
conversationStorage.Setup(s => s.GetHistory(It.IsAny<Guid>())).Returns(history);
// Act
_sut = _fixture.Create<ConversationMetadataGenerator>();
await _sut.UpdateMetadata(Guid.NewGuid());
// Assert
Assert.That(history.Messages.Count, Is.GreaterThan(0));
foreach (var message in history.Messages)
{
summaryGeneratorMock.Verify(x => x.GenerateSummariesFor(
It.Is<string>(s => s.Contains(message.Text))
));
}
}
Here is the same unit test but after modifications:
[Theory, AutoData]
public async Task UpdateMetadata_PassesAllMessagesToSummaryGenerator2(
[Frozen] Mock<IConversationStorage> conversationStorage,
[Frozen] Mock<ISummariesMetadataGenerator> summaryGeneratorMock,
ConversationMetadataGenerator sut,
ConversationHistory history)
{
// Arrange
conversationStorage.Setup(s => s.GetHistory(It.IsAny<Guid>())).Returns(history);
// Act
await sut.UpdateMetadata(Guid.NewGuid());
// Assert
Assert.That(history.Messages.Count, Is.GreaterThan(0));
foreach (var message in history.Messages)
{
summaryGeneratorMock.Verify(x => x.GenerateSummariesFor(
It.Is<string>(s => s.Contains(message.Text))
));
}
}
The result of unit test from the second example is:
AutoFixture.ObjectCreationExceptionWithPath : AutoFixture was unable to create an instance from LlmConversation.Core.Storage.IConversationStorage because it's an interface. There's no single, most appropriate way to create an object implementing the interface, but you can help AutoFixture figure it out.
There is no problem to create an instance of IConversationStorage in the first unit test and at the same time it is not possible to create it in second test. Why is that?
Try using auto-mocking as described in AutoData Theories with AutoFixture, an article in AutoFixture's creator's blog:
and then use
AutoMoqDatainstead ofAutoDatain your test like this: