How can I use variables in my feature file? Specifically, I need to use dateTime.now. Ideally, something like...
Given the API returns items for "dateTime.now"
when my function is run
then I want that data in my database
And in my acceptance test file...
[Given("The API returns line items for (.*)")]
Is this the proper way to go about this? I'm unsure of how to use variables in my feature file. I want my acceptance test to use the current date.
The easiest way is to write a step specific for returning lines items for "right now":
Given the API returns items for right now
You can call the other version of the step from the new version:
[Given(#"the API returns items for right now")]
public void GivenTheAPIReturnsItemsForRightNow()
{
GivenTheAPIReturnsItemsFor(DateTime.Now);
}
This avoids code duplication between steps.
I partially agree with Greg Brughardts answer. Because the feature file is something you can share with business stakeholders (or other non-IT persons in your organisation), it would make more sense to use 'real world' language in your feature files.
Also, when you would pass this to a reporting tool at the end of the test it would be more readable.
I'd approach it like this. The switch statement makes it easy to add other types of dates with real world language:
[Given("The API returns line items for '(.*)'")]
public void GivenTheAPIReturnsItemsForTime(string mydate)
{
switch (mydate)
{
case:"the current date":
HandleApiDateTime(DateTime.Now.ToString("dd-MM-yyyy"))
// pass the current date to the Api handler
break;
case:"yesterday":
HandleApiDateTime(DateTime.Now.AddDays(-1).ToString("dd-MM-yyyy"))
// pass yesterdays date to the Api handler
break;
default:
Console.Writeline("I didnt recognize this command");
// or other error handling
break;
}
}
private void HandleApiDateTime(DateTime mydate)
{
// do your api magic with a date object
}
Your feature file could then look like
Given the API returns items for 'yesterday'
when my function is run
then I want that data in my database
One way , easiest imo, to get current dateTime in your test is [StepArgumentTransformation] and then you can extract date or other things out of it . This way you can use [StepArgumentTransformation] in other steps in your Gherkin like below resulting in less code
Given the API returns items for currentTime
Given the database1 returns items for rightNowTime
Given the database2 returns items for presentTime
Above is just ex , but basically match it with whatever string variable you like
public class binding {
public DateTime datetime;
[Given(#"the API returns items for (.*)")]
[Given(#"Given the database1 returns items for (.*)")]
[Given(#"Given the database2 returns items for (.*)")]
public void currentDatetime(DateTime dt)
{
log.Info("current time: " + datetime);
log.Info("current date: " + datetime.Date);
}
[StepArgumentTransformation]
public DateTime convertToDatetime(string c)
{
datetime = DateTime.Now;
return datetime;
}
}
The above code logs current time and current date three times
Related
Has anyone solved the riddle of how to apply SpecFlow Step Argument Transformations to cells in a table, in conjunction with the SpecFlow.Assist CreateInstance/CreateSet? (code combined here to save space)
Given a table like the following:
| Price | Zip | Effective Date |
| 10.00 | 90210 | in 2 days |
When the 'given' step executes
And the table data populates a poco
Then the effective date should be transformed into a DateTime with value of 2 days from today
[Given(#"a table like the following:")]
public void GivenATableLikeTheFollowing(Table table)
{
var temp = table.CreateInstance<Temp>();
}
internal class Temp
{
decimal Price { get; set; }
int Zip { get; set; }
DateTime EffectiveDate { get; set; }
}
[Binding]
public class Transforms
{
[StepArgumentTransformation(#"in (\d+) days?")]
public DateTime InXDaysTransform(int days)
{
return DateTime.Today.AddDays(days);
}
}
StepArgumentTransformation bindings apparently don't apply to table cell contents (since the step's argument is type Table), but somehow the SpecFlow.Assist CreateInstance/CreateSet will still transform cell data for basic types.
For example , if the Effective Date's contents are '11/13/2016' instead of 'in 2 days', the underlying poco's EffectiveDate property transforms to a DateTime just fine (or an int, decimal, etc).
I see some other solutions like applying a conversion within the step definition itself like here or creating a StepArgumentTransformation for the whole table, but... obvious cons. Update: this question is similar, but solutions also avoid mingling StepArgumentTransformation with CreateInstance/CreateSet.
There is also a section in the SpecFlow Assist Helpers docs about extending by registering value retrievers/comparers, but in my example, a DateTime set already exists. So, perhaps a custom DateTime type? It seems like perhaps there could be a check for StepArgumentTransformations on the known types, or something like that.
In the DateTime retriever, something like..
public virtual DateTime GetValue(string value)
{
var returnValue = DateTime.MinValue;
// check for StepArgumentTransformations here first?
DateTime.TryParse(value, out returnValue);
return returnValue;
}
Any ideas on what I am missing to get the StepArgumentTransformation to apply to the table cell contents when using table.CreateInstance? Or is one of the mentioned solutions the best/only way?
I have created a small prototype that can be used to reconfigure Assist to be able to pick up conversions with [StepArgumentTransformation] bindings.
My plan is to make a blog post about it, but until it is ready, maybe you can get out the essence from this gist. (I did it a year ago for SpecFlow v2.0, so some smaller adaptions might be necessary.)
https://gist.github.com/gasparnagy/a478e5b7ccb8f557a6dc
I don't think what you want is implemented currently, but theoretically I think it could be implemented. You can probably implement a new, enhanced DateTimeValueRetriever yourself which checks to see if the string is parseable as a datetime first and if not checks if any of the [StepArgumentTransformation] methods can parse it, and then replace the current DateTimeValueRetriever with your enhanced one. Then you could submit a pr offering your new version as an enhancement to the existing version, and see what the appetite is.
I have a RDLC report that displays count of Test Packs issued each day. I want to change this report in such a way that it should show the count of test packs issued per week instead of per day. How can i achieve that?
Here is the result of the current report (exported to excel).
The report is generated Island wise, then issue date wise test packs count.
The property in my ViewModel returns a collection that contains Test Pack records with fields like
public class TestPack
{
public string TestPackNo { get;set; }
public string Island { get;set; }
public string IssueDate { get;set; }
}
There two ways to achieve this.
Work with underlying data - for example, add column "MondayofCurrentWeek" (since every week would have Monday) and group by that column instead. (This would be my preferred solution.)
Add group by "week start" expression. You might need to add function to report's code to find it base on current date function. Since the language for report's code is VB, this may help: https://msdn.microsoft.com/en-us/library/aa227527(v=vs.60).aspx
I have a problem on my program, by solving this issue, it maybe can be done by using singleton method. But, i read from some article, they said,it is not a good way to implement it as the asp.net application concurrent users might have a lot.
My problem is,system running number is base on the particular record in the database example:
document_type="INV" , document_year=2015 , document_month=04, document_running=0102.
document_type="INV" , document_year=2015 , document_month=05, document_running=0002.
Therefore, when user create a new record, the logic of getting the new running number as below:
Get the document type = "inv" , current year and current month,
If not found. create a new document type , year and month record with the running number 0001.
if found. running + 1.
now, the problem come out. my situation is 5 users received the record information
as when they pressed "save" button to create a new record:
- document_type="INV" , document_year=2015 , document_month=05, document_running=0002.
and 5 users get the same running number INV15-05-0003 ( after 0002 + 1).
By right, should be INV15-05-0003, INV15-05-0004, INV15-05-0005, INV15-05-0006 and INV15-05-0007.
how we should do to avoid if all users getting the wrong/outdated information.
hope you all able to understand on my poor english.
Regards,
MH
The only way I see is to use a lock on the method you are calling to do the database management.
public class Dal
{
private static object syncObject = new object();
public static void InsertUpdate(...)
{
lock (syncObject)
{
// 1. Get the document type = "inv" , current year and current month,
// 2. If not found. create a new document type , year and month record with the running number 0001.
// 3. if found. running + 1.
}
}
}
The simplest way you can get close to desired effect is to use Auto Incrementing for document_running field: https://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html.
Warning: Be aware, in this case your document_running is always going to be unique across all documents, not just for the records with the same type/year/month.
Alternative solution:
Use GUID as document_running field. The same warning applies.
I am using the repository pattern to query SQL to get a record based on a date passed in via a web api. The query string is date=2014-09-16, for example. When my repository receives this date, the time is automatically set to 12:00:00 since one wasn't passed. I am only interested in matching the date in the database like this:
public IQueryable<Instance> GetInstances(DateTime date) {
return DBContext.Instances.Where(x => x.StartDateTime == date).OrderBy(x => x.StartDateTime).AsQueryable();
}
The problem is that no match is found since the records in the db are not a full match because of the time portion even though records exist for this date. What is the best way to get a match in the above example?
Here are all the default .NET methods EF supports. Only these are supported. If you want something else, you have to use these date functions: Entity Framework sqlFunctions, or put your code in a stored procedure or table function (which can be called by the context).
I have a user defined function that takes 2 datetime parameters and returns a short.
I've added it to my Linq to Sql model, which means I have a function like below:
private short? Aqua_NumShopDays(System.Nullable<System.DateTime> start,
System.Nullable<System.DateTime> end)
So, my question is, how can I call this for multiple date pairs easily (in a LINQy type way) that causes only one trip to the database?
If needed instead of a list of dates, it would still be useful if the first parameter was fixed, and the second parameter was every value in a given range.
Best I've found so far is to create a table (or user function that creates one) that has a range of numbers, then use that in Linq-To-SQL, as below:
// NumberRange is my user defined function, that returns a table with all a row per number
// Here I take that number and calculate the date based on an offset from today
var test = from dayOffset in ARDC.NumberRange(1, 10)
select DateTime.Today.AddDays(dayOffset.Counter.Value); // Counter is the column name of the table returned
// Using the dates, that are calculated on the server, I select a call to the SQL function
var testResults = from toDate in test
select ARDC.Aqua_NumShipDays(DateTime.Today, toDate).Value;
var t = testResults.ToList(); // This results in ONE trip to the database! (yay!)