C
C#•14mo ago
LazyGuard

How to test this code?

I am trying to refactor some code in a background service that looks like this:
public class MyBackgroundService : BackgroundService {
public MyBackgroundService(IKafkaConsumer consumer, IOptionMonithor<WorkerConfig> config, NotificationSender sender)
{
_consumer = consumer;
_config = config;
_sender = sender;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
await ConsumeKafkaAndSendNotificationAsync();
await Task.Delay(TimeSpan.FromMilliseconds(_config.CurrentValue.Delay), stoppingToken);
}
}

private async Task ConsumeKafkaAndSendNotificationAsyncc()
{
var timer = new StopWatch();
timer.Start();
Message? message;
do
{
message = _consumer.ConsumeMessage();
// .....
// do some work here on the message
// .....
await _sender.SendNotificationAsync(message);
} while (
message != null && timer.Elapsed < TimeSpan.FromMilliseconds(_config.CurrentValue.Delay)
)
}
}
public class MyBackgroundService : BackgroundService {
public MyBackgroundService(IKafkaConsumer consumer, IOptionMonithor<WorkerConfig> config, NotificationSender sender)
{
_consumer = consumer;
_config = config;
_sender = sender;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
await ConsumeKafkaAndSendNotificationAsync();
await Task.Delay(TimeSpan.FromMilliseconds(_config.CurrentValue.Delay), stoppingToken);
}
}

private async Task ConsumeKafkaAndSendNotificationAsyncc()
{
var timer = new StopWatch();
timer.Start();
Message? message;
do
{
message = _consumer.ConsumeMessage();
// .....
// do some work here on the message
// .....
await _sender.SendNotificationAsync(message);
} while (
message != null && timer.Elapsed < TimeSpan.FromMilliseconds(_config.CurrentValue.Delay)
)
}
}
Complex work should usually be kept somewhere else outside of the loop of the backgroundService. However, things get hairy enough that some tests will help.
2 Replies
LazyGuard
LazyGuardOP•14mo ago
To test the code, II mocked the consumer and i have a lot of tests like this
[Fact]
public async Task Should_Assert_That_Some_Work_Is_Done()
{
// Arrange
var message = new Mesagge(...);
MockedConsumer.ConsumeMessage().ReturnsForAnyArgs(x =>message, x =>null));

Notification? sentNotification = null;
MockedSender.SendNotificationAsync(Arg.Do<Notification>(x => sentNotification = x)).Returns(Task.CompletedTask);

// Act
Task.Delay(Configuration.Delay + 100).Wait();

//Assert
// Some assertions on the work being done
Assert.NotNull(sentNotification?.Message?.Price);

}
[Fact]
public async Task Should_Assert_That_Some_Work_Is_Done()
{
// Arrange
var message = new Mesagge(...);
MockedConsumer.ConsumeMessage().ReturnsForAnyArgs(x =>message, x =>null));

Notification? sentNotification = null;
MockedSender.SendNotificationAsync(Arg.Do<Notification>(x => sentNotification = x)).Returns(Task.CompletedTask);

// Act
Task.Delay(Configuration.Delay + 100).Wait();

//Assert
// Some assertions on the work being done
Assert.NotNull(sentNotification?.Message?.Price);

}
When I launch tests, the majority fail and I am trying to wrap my head around and understand why. When Launching tests individually, they all pass ! Observations: 1. Some tests fail with a null value when a non null value is expected 2. Some tests fail with a value that is not null but different from the expected. Any help ? 🤔
phaseshift
phaseshift•14mo ago
Is MockedSender static or part of a fixture? If you want to wait until a message is received in a mock then use some form of barrier like ManualResetEvent (instead of doing an arbitrary wait, which btw is not the 'Act' of the test)

Did you find this page helpful?