Refactor QuartzJobTransientRetryTests to use manual job instances consistently#106
Merged
sfmskywalker merged 2 commits intoenh/102from Dec 24, 2025
Merged
Refactor QuartzJobTransientRetryTests to use manual job instances consistently#106sfmskywalker merged 2 commits intoenh/102from
sfmskywalker merged 2 commits intoenh/102from
Conversation
…ests The test now explicitly separates two scenarios: - Transient exceptions: test Execute() directly without scheduling - Non-transient exceptions: schedule job to verify deletion behavior This clarifies that we're testing the job Execute logic directly with test doubles, while only scheduling when needed to verify scheduler interactions. Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Update Quartz.NET jobs resilience based on review feedback
Refactor QuartzJobTransientRetryTests to use manual job instances consistently
Dec 24, 2025
sfmskywalker
approved these changes
Dec 24, 2025
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors the test setup in QuartzJobTransientRetryTests to make the testing approach more explicit by distinguishing between tests that require Quartz scheduling and those that can test job execution logic directly.
Key Changes:
- Split
CreateTestJobSetupinto two distinct methods:CreateTestJobSetupWithoutSchedulingfor direct execution testing andCreateTestJobSetupWithSchedulingfor scheduler interaction testing - Added comprehensive documentation explaining when each setup method should be used
- Updated test comments to clarify the reason for using each setup approach
Comments suppressed due to low confidence (1)
test/modules/scheduling/Elsa.Scheduling.Quartz.ComponentTests/QuartzJobTransientRetryTests.cs:121
- The two methods CreateTestJobSetupWithoutScheduling and CreateTestJobSetupWithScheduling contain significant code duplication. Consider extracting the common setup logic (lines 78-88 in the first method and 103-113 in the second) into a shared private method, then have each method call that shared method and only handle the scheduling-specific logic. This would reduce maintenance burden and make the code more DRY.
private async Task<(RunWorkflowJob job, FailingWorkflowStarter failingStarter, IJobExecutionContext context)>
CreateTestJobSetupWithoutScheduling(int failuresBeforeSuccess, Exception exception, string jobIdentifier)
{
var scheduler = await WorkflowServer.GetSchedulerAsync();
var workflowStarter = Scope.ServiceProvider.GetRequiredService<IWorkflowStarter>();
var failingStarter = new FailingWorkflowStarter(workflowStarter)
{
FailuresBeforeSuccess = failuresBeforeSuccess,
ExceptionToThrow = exception
};
var job = CreateRunWorkflowJob(failingStarter);
var (jobDetail, trigger) = CreateJobDetailAndTrigger(jobIdentifier);
// Don't schedule with Quartz - we're testing the Execute method directly
var context = CreateTestContext(scheduler, jobDetail, trigger);
return (job, failingStarter, context);
}
/// <summary>
/// Creates a test setup and schedules the job with Quartz.
/// Use when testing behavior that involves scheduler operations (e.g., job deletion).
/// </summary>
private async Task<(RunWorkflowJob job, FailingWorkflowStarter failingStarter, IJobExecutionContext context)>
CreateTestJobSetupWithScheduling(int failuresBeforeSuccess, Exception exception, string jobIdentifier)
{
var scheduler = await WorkflowServer.GetSchedulerAsync();
var workflowStarter = Scope.ServiceProvider.GetRequiredService<IWorkflowStarter>();
var failingStarter = new FailingWorkflowStarter(workflowStarter)
{
FailuresBeforeSuccess = failuresBeforeSuccess,
ExceptionToThrow = exception
};
var job = CreateRunWorkflowJob(failingStarter);
var (jobDetail, trigger) = CreateJobDetailAndTrigger(jobIdentifier);
// Schedule the job with Quartz so the job can interact with the scheduler
// (e.g., delete itself on non-transient exceptions)
await scheduler.ScheduleJob(jobDetail, trigger);
var context = CreateTestContext(scheduler, jobDetail, trigger);
return (job, failingStarter, context);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The component tests were creating manual job instances with test doubles but also scheduling separate instances with Quartz, creating ambiguity about which instance was being tested.
Changes
Split test setup into two explicit methods:
CreateTestJobSetupWithoutScheduling: Tests Execute() logic directly without scheduler interactionCreateTestJobSetupWithScheduling: Schedules job when verifying scheduler operations (e.g., job deletion)Added documentation clarifying when scheduling is necessary vs. when direct Execute() calls suffice
Before:
After:
All tests remain functionally equivalent but intent is now explicit.
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.