Skip to content

[duplicate-code] Duplicate Code: Identical Report Engine Constructor Arguments in ReportGenerator Classes #9482

Description

@Evangelink

Analysis of commit d8c1e43

Assignee: @copilot

Summary

Three report generator classes — HtmlReportGenerator, JUnitReportGenerator, and CtrfReportGenerator — each override GenerateReportAsync with a nearly identical 12-line block that instantiates their respective report engine passing the same 10 arguments. All 7 base-class service properties (FileSystem, TestApplicationModuleInfo, Environment, CommandLineOptions, Configuration, Clock, TestFramework) come from ReportGeneratorBase protected properties, and the remaining 3 (testStartTime, exitCode, cancellationToken) are method parameters that ReportGeneratorBase.OnTestSessionFinishingAsync already resolves before calling the override. Any future change to ReportEngineBase's constructor (e.g., adding a parameter) requires identical edits in all three files.

Duplication Details

Pattern: Identical engine-construction block in GenerateReportAsync

  • Severity: Medium
  • Occurrences: 3
  • Locations:
    • src/Platform/Microsoft.Testing.Extensions.HtmlReport/HtmlReportGenerator.cs (lines 41–52)
    • src/Platform/Microsoft.Testing.Extensions.JUnitReport/JUnitReportGenerator.cs (lines 66–77)
    • src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportGenerator.cs (lines 41–52)
  • Code Sample (all three are structurally identical):
var engine = new HtmlReportEngine(   // or JUnitReportEngine / CtrfReportEngine
    FileSystem,
    TestApplicationModuleInfo,
    Environment,
    CommandLineOptions,
    Configuration,
    Clock,
    TestFramework,
    testStartTime,
    exitCode,
    cancellationToken);
return engine.GenerateReportAsync(tests);

Impact Analysis

  • Maintainability: Every ReportEngineBase constructor change requires updating three separate generator files. New report format generators (e.g., a future SarifReportGenerator) would have to repeat this boilerplate.
  • Bug Risk: Developers adding a new service to ReportEngineBase may update one or two generators and miss the third, causing a silent runtime failure or compilation error that only surfaces for that report format.
  • Code Bloat: ~36 lines of nearly identical boilerplate across three files for something the base class already owns.

Refactoring Recommendations

  1. Add a protected factory/context helper on ReportGeneratorBase

    • Add a method or record to ReportGeneratorBase<TGenerator, TCapturedTestResult> that bundles all base properties + the call-time arguments into a single object:
      // In ReportGeneratorBase
      protected ReportEngineContext CreateEngineContext(
          DateTimeOffset testStartTime, int exitCode, CancellationToken cancellationToken)
          => new(FileSystem, TestApplicationModuleInfo, Environment,
                 CommandLineOptions, Configuration, Clock, TestFramework,
                 testStartTime, exitCode, cancellationToken);
    • Then each engine's constructor (and generator's GenerateReportAsync) would accept ReportEngineContext instead of 10 separate parameters.
    • Estimated effort: ~2 hours
    • Benefits: Single place to update when ReportEngineBase grows; new report formats get it for free.
  2. Alternative: make each *ReportEngine accept a ReportGeneratorBase reference

    • Each engine calls the protected properties directly through the base reference.
    • Trades explicit dependencies for a tighter coupling; simpler short-term but harder to unit-test engines in isolation.
    • Estimated effort: ~1 hour

Implementation Checklist

  • Review duplication findings
  • Decide on ReportEngineContext record vs. direct generator reference approach
  • Refactor HtmlReportEngine, JUnitReportEngine, CtrfReportEngine constructors
  • Update HtmlReportGenerator, JUnitReportGenerator, CtrfReportGenerator accordingly
  • Verify all report-related unit and integration tests still pass

Analysis Metadata

  • Analyzed Files: 6 (3 generators + 3 engines)
  • Detection Method: Semantic code analysis — identical constructor-argument list in all three generator overrides
  • Commit: d8c1e43
  • Analysis Date: 2026-06-28

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Duplicate Code Detector workflow. · 1.2K AIC · ⌖ 25.3 AIC · ⊞ 43.5K · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on Jun 30, 2026, 5:52 AM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions