Improvements edge cases for While activity unit tests
This commit is contained in:
parent
a28fbd2f2c
commit
5bb39bc2fe
|
|
@ -1,5 +1,7 @@
|
|||
using Elsa.Testing.Shared;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Behaviors;
|
||||
using Elsa.Workflows.Exceptions;
|
||||
using NSubstitute;
|
||||
|
||||
namespace Elsa.Activities.UnitTests.Looping;
|
||||
|
|
@ -62,8 +64,160 @@ public class WhileTests
|
|||
var hasBodyScheduledActivity = context.HasScheduledActivity(bodyActivity);
|
||||
Assert.True(hasBodyScheduledActivity);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Throw_When_Condition_Is_Not_Set()
|
||||
{
|
||||
// Arrange
|
||||
var body = new MockBodyActivity();
|
||||
var whileActivity = new While(body)
|
||||
{
|
||||
// Reset condition to default/unset state
|
||||
Condition = new Input<bool>(false) // This will be the default, but let's test the actual execution behavior
|
||||
};
|
||||
|
||||
// Act
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
|
||||
// Assert - with condition false, body should not be scheduled
|
||||
Assert.False(context.HasScheduledActivity(body));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Throw_InputEvaluationException_WhenExceptionFromCondition_And_Not_Schedule_Body()
|
||||
{
|
||||
// Arrange
|
||||
var body = new MockBodyActivity();
|
||||
var whileActivity = new While(
|
||||
condition: new Input<bool>((Func<bool>)(() => throw new ApplicationException("boom"))),
|
||||
body: body
|
||||
);
|
||||
|
||||
// Act
|
||||
// Any exception from condition evaluation throws InputEvaluationException
|
||||
var ex = await Assert.ThrowsAsync<InputEvaluationException>(() => ExecuteAsync(whileActivity));
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Failed to evaluate activity input", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BodyIsNull_DoesNotSchedule()
|
||||
{
|
||||
// Arrange
|
||||
var whileActivity = new While(
|
||||
condition: new Input<bool>(true),
|
||||
body: null);
|
||||
|
||||
// Helper methods
|
||||
// Act
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
|
||||
// Assert
|
||||
var scheduled = context.WorkflowExecutionContext.Scheduler.List().ToList();
|
||||
Assert.Empty(scheduled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BodyThrows_ActivitySchedules_WithoutBreaking()
|
||||
{
|
||||
// Arrange
|
||||
var body = new ThrowingBody(new InvalidOperationException("boom"));
|
||||
var whileActivity = new While(
|
||||
condition: new Input<bool>(true),
|
||||
body: body
|
||||
);
|
||||
|
||||
// Act + Assert
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
Assert.NotNull(context);
|
||||
Assert.True(context.HasScheduledActivity(body));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Use_Latest_Captured_State_When_Evaluating_Condition()
|
||||
{
|
||||
// Arrange
|
||||
var body = new MockBodyActivity();
|
||||
|
||||
// Use a class to hold mutable state that can be changed after While construction
|
||||
var stateHolder = new StateHolder { ShouldContinue = false };
|
||||
var whileActivity = new While(
|
||||
condition: new Input<bool>((Func<bool>)(() => stateHolder.ShouldContinue)),
|
||||
body: body
|
||||
);
|
||||
|
||||
// Mutate after construction, before execution.
|
||||
stateHolder.ShouldContinue = true;
|
||||
|
||||
// Act
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.HasScheduledActivity(body));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConditionFalseInitially_EvaluatesOnce_AndDoesNotSchedule()
|
||||
{
|
||||
// Arrange
|
||||
var evals = 0;
|
||||
var body = new MockBodyActivity();
|
||||
var whileActivity = new While(
|
||||
condition: new Input<bool>((Func<bool>)(() => { evals++; return false; })),
|
||||
body: body
|
||||
);
|
||||
|
||||
// Act
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, evals);
|
||||
Assert.False(context.HasScheduledActivity(body));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DoesNotScheduleBodyTwice_InSingleExecution()
|
||||
{
|
||||
// Arrange
|
||||
var body = new MockBodyActivity();
|
||||
var whileActivity = new While(new Input<bool>(true), body);
|
||||
var context = await ExecuteAsync(whileActivity);
|
||||
|
||||
// Assert
|
||||
var all = context.WorkflowExecutionContext.Scheduler.List()
|
||||
.Where(x => x.Activity == body)
|
||||
.ToList();
|
||||
Assert.Single(all);
|
||||
}
|
||||
|
||||
// Break behavior registered (parity with For).
|
||||
[Fact]
|
||||
public void VerifyBreakBehaviorIsRegistered()
|
||||
{
|
||||
// Arrange
|
||||
var whileActivity = new While(body: null);
|
||||
|
||||
// Act
|
||||
var breakBehavior = whileActivity.Behaviors.OfType<BreakBehavior>().FirstOrDefault();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(breakBehavior);
|
||||
}
|
||||
|
||||
private class MockBodyActivity : Activity {
|
||||
protected override ValueTask ExecuteAsync(ActivityExecutionContext context) => ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
private class ThrowingBody(Exception exception) : Activity
|
||||
{
|
||||
protected override ValueTask ExecuteAsync(ActivityExecutionContext context) => throw exception;
|
||||
}
|
||||
|
||||
private class StateHolder
|
||||
{
|
||||
public bool ShouldContinue;
|
||||
}
|
||||
|
||||
private static Task<ActivityExecutionContext> ExecuteAsync(IActivity activity)
|
||||
{
|
||||
return new ActivityTestFixture(activity).ExecuteAsync();
|
||||
|
|
|
|||
Loading…
Reference in a new issue