perf: optimize ExcelIO tests with fixture-based consolidation
- Add WorkbookFixtureBase and 4 concrete fixtures for shared workbooks - Add ExcelTestHelpers with shared utility methods - Create Integration/ folder with 7 fixture-based test classes: - MinimalSearchTests (5 tests) - SearchResultsSheetTests (5 tests) - MisInfoSheetTests (11 tests) - InvestigationSheetTests (7 tests) - ProtectionAndStyleTests (7 tests) - LegacyFormatTests (5 tests) - LargeDataSetTests (1 test) - Delete redundant ExcelExportIntegrationTests.cs (26 tests) - Delete redundant LegacyComparisonTests.cs (16 tests) - Reduce workbook generations from ~42 to 4 fixtures - Test runtime reduced from ~18 min to ~4 min (76% improvement) - All 122 ExcelIO tests pass
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public static class ExcelTestHelpers
|
||||
{
|
||||
public static List<string> GetHeadersFromSheet(IXLWorksheet sheet)
|
||||
{
|
||||
var headers = new List<string>();
|
||||
var col = 1;
|
||||
while (!sheet.Cell(1, col).IsEmpty())
|
||||
{
|
||||
headers.Add(sheet.Cell(1, col).Value.GetText());
|
||||
col++;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.ExcelIO.Models.Reporting;
|
||||
using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public class LargeDataSetFixture : WorkbookFixtureBase
|
||||
{
|
||||
protected override SearchModel CreateSearchModel()
|
||||
{
|
||||
var model = new SearchModel
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Large Data Set Test",
|
||||
UserName = "testuser",
|
||||
SubmitDt = new DateTime(2024, 1, 15, 14, 30, 45),
|
||||
StartDt = new DateTime(2024, 1, 15, 14, 31, 0),
|
||||
EndDt = new DateTime(2024, 1, 15, 14, 35, 0),
|
||||
ExtractMisData = false,
|
||||
Results = []
|
||||
};
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
model.Results.Add(new SearchResult
|
||||
{
|
||||
WorkOrderNumber = 10000 + i,
|
||||
ItemNumber = $"ITEM-{i:D5}",
|
||||
LotNumber = $"LOT-{i:D5}",
|
||||
Flagged = true
|
||||
});
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using JdeScoping.ExcelIO.Models.Reporting;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public class MinimalSearchFixture : WorkbookFixtureBase
|
||||
{
|
||||
protected override SearchModel CreateSearchModel() => new()
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Minimal Search Test",
|
||||
UserName = "testuser",
|
||||
SubmitDt = new DateTime(2024, 1, 15, 14, 30, 45),
|
||||
StartDt = new DateTime(2024, 1, 15, 14, 31, 0),
|
||||
EndDt = new DateTime(2024, 1, 15, 14, 35, 0),
|
||||
ExtractMisData = false,
|
||||
Results = []
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using JdeScoping.ExcelIO.Models.Reporting;
|
||||
using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
|
||||
using MisSearchResult = JdeScoping.Core.Models.SearchResults.MisSearchResult;
|
||||
using MisNonMatchSearchResult = JdeScoping.Core.Models.SearchResults.MisNonMatchSearchResult;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public class WithMisDataFixture : WorkbookFixtureBase
|
||||
{
|
||||
protected override SearchModel CreateSearchModel() => new()
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Search With MIS Data",
|
||||
UserName = "testuser",
|
||||
SubmitDt = new DateTime(2024, 1, 15, 14, 30, 45),
|
||||
StartDt = new DateTime(2024, 1, 15, 14, 31, 0),
|
||||
EndDt = new DateTime(2024, 1, 15, 14, 35, 0),
|
||||
ExtractMisData = true,
|
||||
Results =
|
||||
[
|
||||
new SearchResult
|
||||
{
|
||||
WorkOrderNumber = 12345,
|
||||
WorkOrderBranchCode = "001",
|
||||
LotNumber = "LOT-001",
|
||||
ItemNumber = "ITEM-001",
|
||||
PlanningFamily = "PF01",
|
||||
StockingType = "M",
|
||||
OrderQuantity = 100,
|
||||
HeldQuantity = 0,
|
||||
ScrappedQuantity = 0,
|
||||
ShippedQuantity = 50,
|
||||
StepBranchCode = "001",
|
||||
StepNumber = 10,
|
||||
StepDescription = "Assembly",
|
||||
FunctionOperationDescription = "Main assembly",
|
||||
StepUpdateDt = new DateTime(2024, 1, 14, 10, 0, 0),
|
||||
StatusCode = "50",
|
||||
StatusDescription = "In Progress",
|
||||
Flagged = true
|
||||
}
|
||||
],
|
||||
MisResults =
|
||||
[
|
||||
new MisSearchResult
|
||||
{
|
||||
ItemNumber = "ITEM-001",
|
||||
SequenceNumber = "010",
|
||||
MisNumber = "MIS-001",
|
||||
RevId = "A",
|
||||
ItemDescription = "Test Item",
|
||||
Status = "Released",
|
||||
ReleaseDate = new DateTime(2023, 12, 15),
|
||||
BranchCode = "001",
|
||||
JobStepSequenceNumber = 10,
|
||||
MatchedSequenceNumber = 10,
|
||||
RoutingMatch = true,
|
||||
MasterMatch = true,
|
||||
FunctionOperationDescription = "Assembly operation",
|
||||
CharNumber = "001",
|
||||
TestDescription = "Sample test description",
|
||||
SamplingType = "100%",
|
||||
SamplingValue = "1",
|
||||
ToolsGauges = "Gauge A, Gauge B",
|
||||
WorkInstructions = "Step 1: Do this. Step 2: Do that."
|
||||
}
|
||||
],
|
||||
MisNonMatchResults =
|
||||
[
|
||||
new MisNonMatchSearchResult
|
||||
{
|
||||
WorkCenterCode = "WC01",
|
||||
WorkOrderNumber = 12345,
|
||||
WorkOrderStartDate = new DateTime(2024, 1, 8),
|
||||
JobStepNumber = 10,
|
||||
JobStepDescription = "Test operation",
|
||||
JobStepEndDate = new DateTime(2024, 1, 10),
|
||||
FunctionCode = "FC01",
|
||||
WasJobStepAdded = false,
|
||||
MatchedJobStepNumber = 10,
|
||||
ItemNumber = "ITEM-001",
|
||||
ItemDescription = "Test Item Description",
|
||||
RoutingType = "M"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using JdeScoping.ExcelIO.Models.Reporting;
|
||||
using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public class WithResultsFixture : WorkbookFixtureBase
|
||||
{
|
||||
protected override SearchModel CreateSearchModel() => new()
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Search With Results",
|
||||
UserName = "testuser",
|
||||
SubmitDt = new DateTime(2024, 1, 15, 14, 30, 45),
|
||||
StartDt = new DateTime(2024, 1, 15, 14, 31, 0),
|
||||
EndDt = new DateTime(2024, 1, 15, 14, 35, 0),
|
||||
ExtractMisData = false,
|
||||
Results =
|
||||
[
|
||||
new SearchResult
|
||||
{
|
||||
WorkOrderNumber = 12345,
|
||||
WorkOrderBranchCode = "001",
|
||||
LotNumber = "LOT-001",
|
||||
ItemNumber = "ITEM-001",
|
||||
PlanningFamily = "PF01",
|
||||
StockingType = "M",
|
||||
OrderQuantity = 100,
|
||||
HeldQuantity = 0,
|
||||
ScrappedQuantity = 0,
|
||||
ShippedQuantity = 50,
|
||||
StepBranchCode = "001",
|
||||
StepNumber = 10,
|
||||
StepDescription = "Assembly",
|
||||
FunctionOperationDescription = "Main assembly operation",
|
||||
StepUpdateDt = new DateTime(2024, 1, 14, 10, 0, 0),
|
||||
StatusCode = "50",
|
||||
StatusDescription = "In Progress",
|
||||
StatusUpdateDt = new DateTime(2024, 1, 14, 10, 0, 0),
|
||||
Flagged = true
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using ClosedXML.Excel;
|
||||
using JdeScoping.ExcelIO.Generators;
|
||||
using JdeScoping.ExcelIO.Mapping;
|
||||
using JdeScoping.ExcelIO.Mapping.Maps;
|
||||
using JdeScoping.ExcelIO.Models.Reporting;
|
||||
using JdeScoping.ExcelIO.Options;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Tests.Fixtures;
|
||||
|
||||
public abstract class WorkbookFixtureBase : IDisposable
|
||||
{
|
||||
public XLWorkbook Workbook { get; }
|
||||
public SearchModel SearchModel { get; }
|
||||
|
||||
protected abstract SearchModel CreateSearchModel();
|
||||
|
||||
protected WorkbookFixtureBase()
|
||||
{
|
||||
SearchModel = CreateSearchModel();
|
||||
var service = CreateExportService();
|
||||
var bytes = service.GenerateAsync(SearchModel).GetAwaiter().GetResult();
|
||||
Workbook = new XLWorkbook(new MemoryStream(bytes));
|
||||
}
|
||||
|
||||
private static ExcelExportService CreateExportService()
|
||||
{
|
||||
var logger = Substitute.For<ILogger<ExcelExportService>>();
|
||||
var options = Microsoft.Extensions.Options.Options.Create(new ExcelExportOptions
|
||||
{
|
||||
CriteriaSheetPassword = "TestCriteriaPass",
|
||||
DataSheetPassword = "TestDataPass"
|
||||
});
|
||||
|
||||
var registry = CreateTestRegistry();
|
||||
var tableWriter = new FluentTableWriter(registry);
|
||||
var criteriaGenerator = new CriteriaSheetGenerator(options, tableWriter);
|
||||
|
||||
return new ExcelExportService(logger, options, criteriaGenerator, tableWriter, registry);
|
||||
}
|
||||
|
||||
private static ExcelMapRegistry CreateTestRegistry()
|
||||
{
|
||||
var registry = new ExcelMapRegistry();
|
||||
|
||||
registry.Register(new SearchResultMap());
|
||||
registry.Register(new MisSearchResultMap());
|
||||
registry.Register(new MisNonMatchSearchResultMap());
|
||||
registry.Register(new TimespanFilterMap());
|
||||
registry.Register(new WorkOrderFilterEntryMap());
|
||||
registry.Register(new ItemNumberFilterEntryMap());
|
||||
registry.Register(new ProfitCenterFilterEntryMap());
|
||||
registry.Register(new WorkCenterFilterEntryMap());
|
||||
registry.Register(new OperatorFilterEntryMap());
|
||||
registry.Register(new ComponentLotFilterEntryMap());
|
||||
registry.Register(new ItemOperationMisFilterEntryMap());
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Workbook.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user