I'm new to our organisation's testing and development suite. It's all in Visual Studio and the automated testing is carried out using SpecFlow (and maybe NuGet v2?).
We have ETL processes that (in a nutshell) takes inputs from Excel files, writes to a DB and produces various output files. The specific bits of the tests (.feature files) I'm looking at are in the form:
Then the CSV file 'filename.csv' in the Outputs directory contains the following content
| Period | Org Ref | Org Name | Question | Answer |
| APR2020 | XXX | XXX | Q1 | No |
We've had a request to include a timestamp in some of our outputs, but as a timestamp, by its very nature, changes every time it's run, we can't get it to pass these feature tests, and thus it can't be promoted to Live.
Without digging into the underlying C# (expertise in this area is thin on the ground in our org), is it possible to allow certain fields to accept any data, or to maybe include a regex pattern check, rather than an exact match.
Any help greatly appreciated. And apologies if this is a duplicate, given my lack of knowledge the tools I'm using, I've spent tree days fruitlessly searching, and most results assume a fair amount of prior knowledge.
Cheers!
This is an interesting problem I also ran into a while back. I wasn't processing Excel files, rather I had a When
step that did something "right now", and a Then
step that asserted it happened "right now".
I had to settle on "right now-ish" — no less than 3 seconds before right now and no more than 3 seconds after right now.
This should give your test enough padding to do stuff, and then assert. If not, just adjust the your window of time.
First, a modification to your step:
Then the CSV file 'filename.csv' in the Outputs directory contains the following content
| Timestamp | Period | Org Ref | Org Name | Question | Answer |
| Now | APR2020 | XXX | XXX | Q1 | No |
The "Timestamp" column will just be a string
value in C#. Then you can convert that string value to the current date and time. You'll need a few utility methods for the conversion and comparison:
public static class DateTimeUtils
{
/// <summary>
/// Converts this string to DateTime, taking in to account relative terms like "now" and "yesterday".
/// </summary>
public static DateTime ConvertToRelativeDateTime(this string text)
{
switch (text.ToLower())
{
case "now":
return DateTime.UtcNow; // Or DateTime.Now for a time zone specific "now"
case "tomorrow":
return DateTime.Today.AddDays(1);
case "yesterday":
return DateTime.Today.AddDays(-1);
default:
return DateTime.Parse(text);
}
}
/// <summary>
/// Returns whether or not this DateTime is "right now," give or take a few seconds either side of "now".
/// </summary>
public static bool IsNowIsh(this DateTime date, int numberOfSecondsToGiveOrTake = 3)
{
var now = DateTime.Now;
var min = now.AddSeconds(numberOfSecondsToGiveOrTake * -1);
var max = now.AddSeconds(numberOfSecondsToGiveOrTake);
return date >= min && date <= max;
}
}
And finally your step definition:
[Then(@"Then the CSV file '(.*)' in the Outputs directory contains the following content")]
public void ThenTheCSVFileInTheOutputsDirectoryContainsTheFollowingContent(string filename, Table table)
{
// ...
foreach (var row in table.Rows)
{
var timestamp = row["Timestamp"].ConvertToRelativeDateTime();
var isNow = timestamp.IsNowIsh(); // Returns true if timestamp is within 3 seconds before or 3 seconds after right now
// ...
}
}
If your test falls fails because the timestamp
is more than 3 seconds off, then call it with an int
argument to adjust the padding in seconds:
var isNow = timestamp.IsNowIsh(5); // Returns true if timestamp is no less than 5 seconds before now and no more than 5 seconds after now
The trick is to get just enough precision so your test consistently passes while giving you the confidence that it verifies the time stamp "good enough." You won't ever get it perfect.