I have a test script that does something to one object then the same thing to a second object. This continues for quite a while. With so much predictable repetition that it seems ripe for automation but I can't figure out how. I wouldn't care so much except with so much repetition, it's easy to overlook using the wrong variable (ie: stagingXyz when prodXyz was intended.)
The details below are irrelevant. What's important is the pattern.
var stagingDbs = cleanupDbs(stagingServer.Databases);
var prodDbs = cleanupDbs(prodServer.Databases);
printDiff(stagingDbs, prodDbs, "Databases mis-matched");
foreach (var db in stagingDbs.Intersect(prodDbs)) {
var stagingDb = stagingServer.Databases[db];
var prodDb = prodServer.Databases[db];
var stagingTables = cleanupTables(stagingDb.Tables);
var prodTables = cleanupTables(prodDb.Tables);
printDiff(stagingTables, prodTables, "Tables mis-matched on " + db);
foreach (var table in stagingTables.Intersect(prodTables)) {
var stagingTable = stagingDb.Tables[table];
var prodTable = prodDb.Tables[table];
var matchedColumns = stagingColumns.Intersect(prodColumns);
var stagingTableColumns = stagingTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
var prodTableColumns = prodTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
printDiff(stagingTableColumns, prodTableColumns,
"Columns mis-matched");
}
}
I don't want to go through, for instance, replacing this
var stagingTableColumns = stagingTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
var prodTableColumns = prodTable.Columns
.Cast<Column>()
.Where(c => matchedColumns.Contains(c.Name))
.Select(c => formatColumn(c));
with this
var stagingTableColumns = doStuff(stagingTable, matchedColumns);
var prodTableColumns = doStuff(prodTable, matchedColumns);
because I have to make sure everything in the 1st line is stagingXyz
and the 2nd line is prodXyz
. Not so bad for 1 line but the test script is huge and only ever does one of these 2 things:
- foo(stagingXyz); foo(prodXyz);
- bar(stagingXyz, prodXyz);
Similarly, wrapping with these items in an array and having doStuff[0]; doStuff[1];
is subject to the same easy typo error only a typo with 0 vs. 1 will be even harder to spot at a glance.
I thought about making 2 container objects (one for staging, one for prod) and putting these 2 objects in a collection but I fear this will lead to a bazillion tiny loops that will be very hard to maintain.
Is there anyway to simplify this and still have it be readable and maintainable?