Skip to content

Commit

Permalink
nsb: PoC testing
Browse files Browse the repository at this point in the history
  • Loading branch information
rmandvikar committed Feb 4, 2024
1 parent 2d93045 commit 4ec5ae4
Show file tree
Hide file tree
Showing 5 changed files with 313 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ indent_style = tab
end_of_line = crlf
insert_final_newline = true

[*.csproj]
[{*.csproj,*.props}]
indent_size = 2
indent_style = space
end_of_line = crlf
Expand Down
5 changes: 5 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Net.Http.WinHttpHandler" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
<PackageVersion Include="NServiceBus" Version="7.4.0" />
<PackageVersion Include="NServiceBus.Testing" Version="7.4.2" />
</ItemGroup>
</Project>
299 changes: 299 additions & 0 deletions tests/rm.DelegatingHandlersTest/SagaTesting.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
using AutoFixture;
using AutoFixture.AutoMoq;
using NServiceBus;
using NServiceBus.Testing;
using NUnit.Framework;

namespace NsbTesting;

public class OrderSagaHander :
NServiceBus.Saga<OrderSagaData>,
IAmStartedByMessages<StartOrder>,
IHandleMessages<CompleteOrder>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
{
mapper.MapSaga(saga => saga.OrderId)
.ToMessage<StartOrder>(message => message.OrderId)
.ToMessage<CompleteOrder>(message => message.OrderId)
;
}

public async Task Handle(StartOrder message, IMessageHandlerContext context)
{
Data.DramaProperty = "StartOrder";

// work

//return Task.CompletedTask;
await context.Send(
new CompleteOrder()
{
OrderId = message.OrderId
});
}

public Task Handle(CompleteOrder message, IMessageHandlerContext context)
{
Data.DramaProperty = "CompleteOrder";

// work

//MarkAsComplete();
return Task.CompletedTask;
}
}

public class OrderSagaData :
ContainSagaData
{
public string OrderId { get; set; }

Check warning on line 50 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 50 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public string DramaProperty { get; set; }

Check warning on line 51 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'DramaProperty' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class StartOrder : ICommand
{
public string OrderId { get; set; }

Check warning on line 56 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 56 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
public class CompleteOrder : ICommand
{
public string OrderId { get; set; }

Check warning on line 60 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 60 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class TransactionSagaHander :
NServiceBus.Saga<OrderSagaData>,
IAmStartedByMessages<StartOrder>,
IHandleMessages<Step1Order>,
IHandleMessages<Step2Order>,
IHandleMessages<CompleteOrder>
{
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
{
mapper.MapSaga(saga => saga.OrderId)
.ToMessage<StartOrder>(message => message.OrderId)
.ToMessage<Step1Order>(message => message.OrderId)
.ToMessage<Step2Order>(message => message.OrderId)
.ToMessage<CompleteOrder>(message => message.OrderId)
;
}

public async Task Handle(StartOrder message, IMessageHandlerContext context)
{
Data.DramaProperty = "StartOrder";

// work

//return Task.CompletedTask;
await context.Send(
new Step1Order()
{
OrderId = message.OrderId
});
}

public async Task Handle(Step1Order message, IMessageHandlerContext context)
{
Data.DramaProperty = "Step1Order";

// work

//return Task.CompletedTask;
await context.Send(
new Step2Order()
{
OrderId = message.OrderId
});
}

public async Task Handle(Step2Order message, IMessageHandlerContext context)
{
Data.DramaProperty = "Step2Order";

// work

//return Task.CompletedTask;
await context.Send(
new CompleteOrder()
{
OrderId = message.OrderId
});
}

public Task Handle(CompleteOrder message, IMessageHandlerContext context)
{
Data.DramaProperty = "CompleteOrder";

// work

//MarkAsComplete();
return Task.CompletedTask;
}
}

public class Step1Order : ICommand
{
public string OrderId { get; set; }

Check warning on line 135 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 135 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
public class Step2Order : ICommand
{
public string OrderId { get; set; }

Check warning on line 139 in tests/rm.DelegatingHandlersTest/SagaTesting.cs

View workflow job for this annotation

GitHub Actions / build-workflow / build-job

Non-nullable property 'OrderId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class OrderSagaTests
{
[Test]
public async Task __Verify_SagaData()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var orderSagaData = fixture.Build<OrderSagaData>()
.With(x => x.OrderId, "orderId")
.With(x => x.DramaProperty, "NONE")
.Create();
var handler = new OrderSagaHander
{
Data = orderSagaData
};

var startOrder = fixture.Build<StartOrder>().With(x => x.OrderId, "orderId").Create();
var context = new TestableMessageHandlerContext();

await handler.Handle(startOrder, context);

Assert.AreEqual("orderId", orderSagaData.OrderId);
Assert.AreEqual("StartOrder", orderSagaData.DramaProperty);
}

[Test]
public async Task __Verify_SagaData_Using_Testing()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var orderSagaData = fixture.Build<OrderSagaData>()
.With(x => x.OrderId, "orderId")
.With(x => x.DramaProperty, "NONE")
.Create();
var handler = fixture.Build<OrderSagaHander>().With(saga => saga.Data, orderSagaData).Create();

var testableSaga = new TestableSaga<OrderSagaHander, OrderSagaData>(sagaFactory: () => handler);

var startOrder = fixture.Build<StartOrder>().With(x => x.OrderId, "orderId").Create();
var context = new TestableMessageHandlerContext();

var startOrderResult = await testableSaga.Handle(startOrder, context);

var orderSagaDataSnapshot = startOrderResult.SagaDataSnapshot;

Assert.AreEqual("orderId", orderSagaData.OrderId);
Assert.AreEqual("NONE", orderSagaData.DramaProperty);

Assert.AreEqual("orderId", orderSagaDataSnapshot.OrderId);
Assert.AreEqual("StartOrder", orderSagaDataSnapshot.DramaProperty);

var completeOrder = startOrderResult.FindSentMessage<CompleteOrder>();
Assert.IsNotNull(completeOrder);
Assert.AreEqual("orderId", completeOrder.OrderId);

var completeOrderResult = await testableSaga.Handle(completeOrder, context);

orderSagaDataSnapshot = completeOrderResult.SagaDataSnapshot;

Assert.AreEqual("orderId", orderSagaDataSnapshot.OrderId);
Assert.AreEqual("CompleteOrder", orderSagaDataSnapshot.DramaProperty);
}
}

public class TransactionSagaTests
{
[Test]
public async Task __Verify_Transaction_SagaData()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var orderSagaData = fixture.Build<OrderSagaData>()
.With(x => x.OrderId, "orderId")
.With(x => x.DramaProperty, "NONE")
.Create();
var handler = new TransactionSagaHander
{
Data = orderSagaData
};

var startOrder = fixture.Build<StartOrder>().With(x => x.OrderId, "orderId").Create();
var context = new TestableMessageHandlerContext();

await handler.Handle(startOrder, context);

Assert.AreEqual("orderId", orderSagaData.OrderId);
Assert.AreEqual("StartOrder", orderSagaData.DramaProperty);
}

[Test]
public async Task __Verify_Transaction_SagaData_Using_Testing()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var orderSagaData = fixture.Build<OrderSagaData>()
.With(x => x.OrderId, "orderId")
.With(x => x.DramaProperty, "NONE")
.Create();
var handler = fixture.Build<TransactionSagaHander>().With(saga => saga.Data, orderSagaData).Create();

var testableSaga = new TestableSaga<TransactionSagaHander, OrderSagaData>(sagaFactory: () => handler);

var startOrder = fixture.Build<StartOrder>().With(x => x.OrderId, "orderId").Create();
var context = new TestableMessageHandlerContext();

var startOrderResult = await testableSaga.Handle(startOrder, context);

var orderSagaDataSnapshot = startOrderResult.SagaDataSnapshot;

Assert.AreEqual("orderId", orderSagaData.OrderId);
Assert.AreEqual("NONE", orderSagaData.DramaProperty);

Assert.AreEqual("orderId", orderSagaDataSnapshot.OrderId);
Assert.AreEqual("StartOrder", orderSagaDataSnapshot.DramaProperty);

var step1Order = startOrderResult.FindSentMessage<Step1Order>();
Assert.IsNotNull(step1Order);
Assert.AreEqual("orderId", step1Order.OrderId);

var completeOrderResult = await testableSaga.Handle(step1Order, context);

orderSagaDataSnapshot = completeOrderResult.SagaDataSnapshot;

Assert.AreEqual("orderId", orderSagaDataSnapshot.OrderId);
Assert.AreEqual("Step1Order", orderSagaDataSnapshot.DramaProperty);
}

[Test]
public async Task __Verify_Transaction_SagaData_Using_Testing_Previously()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var orderSagaData = fixture.Build<OrderSagaData>()
.With(x => x.OrderId, "orderId")
.With(x => x.DramaProperty, "NONE")
.Create();
var handler = fixture.Build<TransactionSagaHander>().With(saga => saga.Data, orderSagaData).Create();

var testableSaga = new TestableSaga<TransactionSagaHander, OrderSagaData>(sagaFactory: () => handler);

var step2Order = fixture.Build<Step2Order>().With(x => x.OrderId, "orderId").Create();
var context = new TestableMessageHandlerContext();

// i should be able to run this test picking up from step2,
// step2order -> completeOrder
// so i do not have to construct the whole scenario,
// startOrder -> step1Order -> step2order -> completeOrder
//
// but this test throws,
// System.Exception : Saga not found and message type NsbTesting.Step2Order is not allowed to start the saga.
// this helps to slice the tests into small scenarios versus havin to repeat the scearnios leading up to step2
var startOrderResult = await testableSaga.Handle(step2Order, context);

var orderSagaDataSnapshot = startOrderResult.SagaDataSnapshot;

Assert.AreEqual("orderId", orderSagaDataSnapshot.OrderId);
Assert.AreEqual("Step2Order", orderSagaDataSnapshot.DramaProperty);

var completeOrder = startOrderResult.FindSentMessage<CompleteOrder>();
Assert.IsNotNull(completeOrder);
Assert.AreEqual("orderId", completeOrder.OrderId);
}
}
2 changes: 2 additions & 0 deletions tests/rm.DelegatingHandlersTest/StartOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
namespace rm.DelegatingHandlersTest;

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;net7.0;net48;net472;net462</TargetFrameworks>
<TargetFrameworks>net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand All @@ -26,6 +26,11 @@
<PackageReference Include="System.Net.Http.WinHttpHandler" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="NServiceBus" />
<PackageReference Include="NServiceBus.Testing" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\rm.DelegatingHandlers\rm.DelegatingHandlers.csproj" />
</ItemGroup>
Expand Down

0 comments on commit 4ec5ae4

Please sign in to comment.