Michael Nero
Michael Nero

Reputation: 1416

Testing Activity Compensate with MassTransit

I'm trying to test the compensation logic in my Activity, but I can't figure out how to kick off the Compensate method in a test. I have an activity that should throw an exception if something isn't found in the DB. I've figured out how to ensure that the activity in faulted in this case, but I can't figure out the compensation part.

My test class is below. Note that awaiting on the RoutingSlipActivityCompensated handler throws a TaskCanceledException. How do I test the compensation part of the activity?

[TestClass]
public class DisableTeamCheckInsActivityTests
{
   Mock<ILogger<DisableTeamCheckInsActivity>> _logger;
   CheckInsDbContext _db;

   InMemoryTestHarness _harness;
   ActivityTestHarness<DisableTeamCheckInsActivity, DisableTeamCheckIns, DisableTeamCheckInsLog> _activity;

   [TestInitialize]
   public async Task Initialize()
   {
      _logger = new Mock<ILogger<DisableTeamCheckInsActivity>>();
      _db = CheckInDbContextFactory.Create();

      _harness = new InMemoryTestHarness
      {
         TestTimeout = TimeSpan.FromSeconds(5)
      };

      _activity = _harness.Activity<DisableTeamCheckInsActivity, DisableTeamCheckIns, DisableTeamCheckInsLog>(
         _ => new DisableTeamCheckInsActivity(_logger.Object, _db),
         _ => new DisableTeamCheckInsActivity(_logger.Object, _db)
      );

      await _db.Database.EnsureCreatedAsync();
      await _harness.Start();
   }

   [TestCleanup]
   public async Task Cleanup()
   {
      await _db.Database.EnsureDeletedAsync();
      await _harness.Stop();
   }

   [TestMethod]
   public async Task Missing_Team_Throws()
   {
      var teamId = Guid.NewGuid();

      var builder = new RoutingSlipBuilder(Guid.NewGuid());
      builder.AddSubscription(_harness.BusAddress, RoutingSlipEvents.All);

      var faulted = _harness.SubscribeHandler<RoutingSlipActivityFaulted>();
      var compensated = _harness.SubscribeHandler<RoutingSlipActivityCompensated>();

      builder.AddActivity(_activity.Name, _activity.ExecuteAddress, new
      {
         TeamId = teamId
      });

      await _harness.Bus.Execute(builder.Build());

      var faultContext = await faulted;
      Assert.AreEqual("System.InvalidOperationException", faultContext?.Message?.ExceptionInfo?.ExceptionType);

      await compensated; // <-- This throws a TaskCanceledException
   }
}

Upvotes: 1

Views: 691

Answers (1)

Chris Patterson
Chris Patterson

Reputation: 33447

A routing slip with a single activity will never compensate. If the activity faults, the routing slip faults, but there isn't any compensation information in the routing slip because there were not any previous activities.

If the activity completed, and a subsequent activity faulted, then the compensate method would be called, and the ActivityCompensated event would be published.

Upvotes: 1

Related Questions