What is the best way to compare all properties of two objects where some of them have different formats (e.g. DateTime in one and DateTime.ToString() with custom format in other)?
I was able to do that by using 2 assertions:
o1.ShouldHave().AllPropertiesBut(dto1 => dto1.Date).EqualTo(o2);
o1.Date.Should().Be(DateTime.Parse(o2.Date));
I would think about the following, but that does not compile because EqualTo<T>() is void.
o1.ShouldHave().AllProperties().But(d => d.Date).EqualTo(o2)
.And.Date.Should().Be((DateTime.Parse(o2.Date));
types are:
public class Dto1
{
public int ID { get { return 1; } }
public DateTime Date { get { return DateTime.Now.Date; } }
}
public class Dto2
{
public int ID { get { return 1; } }
public string Date { get { return DateTime.Now.Date.ToShortDateString(); } }
}
var o1 = new Dto1();
var o2 = new Dto2();
The first example is typically the best way. However, if you would switch o1 and o2, it might work in a single call. Fluent Assertions will try to convert (using Convert.ChangeType) the actual value of a property to the expected value of the property with the same name. In your particular example, it would try to convert the DateTime in Dto1 to a string in Dto2 before comparing the values. But since the string representation of a DateTime is dependent on the culture of the thread, it would not give you predictable results. However, if you would switch o1 and o2, I wouldn't be surprised if Convert.ChangeType would succesfully convert your short datetime back to a DateTIme object.
As a side-note, my DTOs usually just pass the DateTime to the caller without any string conversion. I believe that the actual representation of the DateTime is purely a UI responsibility.
HTH
Dennis
Related
I'm going by this tutorial and trying to figure out how to have a DataMember without an auto property. Basically I have a field is a date time in epoch format and I want the property to be a DateTime so I'm trying to do the conversion in the property's get. I'm not sure how to format this exactly.
Since Code was requested please look at the following. :
// The date looks like this in the JSON
"someEpochDateTime": 1428785212000,
// I thought I could work around it using the following code, however
// I get a warning saying someEpochDateTime is never set.
[DataMember(Name = "someEpochDateTime")]
private long someEpochDateTime;
public DateTime test
{
get { return DateTimeConverter.FromUnixTime(someEpochDateTime); }
}
Using FromUnixTime
like this you can create datereturn property this will return date
[DataContract]
public class Mycontractclass
{
// Apply the DataMemberAttribute to the property.
[DataMember]
public DateTime datereturn
{
get
{
return this.dateCreated.HasValue
? this.dateCreated.Value
: DateTime.Now;
}
set { this.dateCreated = value; }
}
private DateTime? dateCreated = null;
}
Apparently my last edit actually works as a solution, I just get a compiler warning for some reason.
[DataMember(Name = "someEpochDateTime")]
private long someEpochDateTime;
public DateTime test
{
get { return DateTimeConverter.FromUnixTime(someEpochDateTime); }
}
I have an object that represents a scheduled payment. My database has a list of these payments, but I have one instance of a payment.
I need to write a method that gets the next payment after the one I have, as well as the previous date of the previous payment.
I'd like to write a method that return the two dates. But the return type of 'DateTime' only allows for one. I could return a List<DateTime> but that seems strange and ma be ambiguous. Which is the previous and which is the next?
I can also create a DTO object that has:
DateTime previousPayment {get; set;}
DateTime nextPayment {get; set;}
Tuple<DateTime, DateTime> might be another options, but it too is ambiguous. Unless I can name the properties of it?
But - is there a better way to allow for a method to return two dates? Anonymous types or something?
Use the "ref" modifier. (You may use "out" instead if you do not need to read the variable before it is assigned)
public void GetNextPayment(ref DateTime previousPayment, ref DateTime nextPayment){
// do stuff here
}
Usage:
DateTime previousPayment = DateTime.Now(); //Example
DateTime nextPayment = DateTime.Now(); // example
GetNextPayment(ref previousPayment, ref nextPayment); // Forgot to add "ref" when calling it
previousPayment and nextPayment will be modified in the function and maintain the value.
Update with Dictionary
As Anik mentioned, it might be better to use a Dictionary;
public Dictionary<string,DateTime> GetNextPayment(DateTime previousPayment, DateTime nextPayment){
// modify payments
Dictionary<string,DateTime> myDict = new Dictionary(string, DateTime);
myDict.Add("PreviousPayment", [date]);
myDict.Add("NextPayment", [date]);
return myDict;
}
Use Class
Ilya. N. mentioned to use a class. I would have to agree with this if you're going to have lots of payment objects going to be used more than once. But I firmly believe it's better to give you all the tools available at your disposal because you never know when you might want to use out parameters or Dictionaries.
public class Payment {
public string Name {get;set;}
public DateTime previousPayment {get;set;}
public DateTime nextPayment {get;set;}
public GetNextPayment(){
// code to get the next payment
this.previousPayment = //whatever
this.nextPayment = //whatever
}
}
If you only have ONE payment you are going to be using, like ever. (good to future proof with a class), then you might use a method or dictionary.
Besides the two options you listed, there are two more:
Return a Tuple<DateTime, DateTime>
Use out parameters
Why not simply return a class?
public class DateCombo {
DateTime PreviousPayment {get; set;}
DateTime NextPayment {get; set;}
}
try this ...
private void Form1_Load(object sender, EventArgs e)
{
DateTime previousPayment =new DateTime();
DateTime nextPayment=new DateTime();
getdate(ref previousPayment, ref nextPayment);
}
public void getdate(ref DateTime previousPayment, ref DateTime nextPayment)
{
previousPayment = System.DateTime.Now;
nextPayment = System.DateTime.Now.AddDays(1);
}
I am attempting to move validation of input data into the get;set; of a class struct.
public void PlotFiles()
{
List<DTVitem.item> dataitems;
DTVitem.item i;
DateTime.TryParse("2012/01/01", out i.dt);
DateTime.TryParse("04:04:04", out i.t);
int.TryParse("455", out i.v);
dataitems.Add(i);
}
The struct is declared in a separate class (probably unnecessary):
public partial class DTVitem
{
public struct item
{
public DateTime dt;
public DateTime t;
public int v;
}
}
Every time I set DTVitem.item.dt, DTVitem.item.t, or DTVitem.item.v, I wish it to perform the relevant .TryParse() to validate the property contents.
However, when I attempt to use TryParse() as follows (attempting to wrap my head around this example from MSDN):
public partial class DTVitem
{
private DateTime _datevalue;
public string dt
{
get { return _datevalue; }
set { DateTime.TryParse(value, out _datevalue) ;}
}
}
I receive the error that _datevalue is a DateTime and cannot be converted to a string. The reason is obviously that the return path must return the type of dt in this instance (a string). However, I have attempted to massage this a few different ways, and am not able to hack it.
How do I achieve my goal of validating a string value as a DateTime when setting it as a property of an instance of the struct?
Is using set as I am attempting to the best way?
I can see that there is a lot of value in using get;set; for validation and would really like to understand it.
Thanks very much,
Matt
[edit]
Thanks to Jon Skeet below for pointing out the err of my ways.
Here's another thread on problems with mutable structs, and another speaking about instantiating a struct. Note structs are value types.
I believe the rest of what he was pointing out is sort of just agreeing that burying the struct way far away isn't necessary, and I should review why I'm doing it.
[solution]
I've taken into account some recommendations below and come up with the following:
public partial class DTVitem
{
private DateTime _dtvalue, _tvalue;
private int _vvalue;
public string dt
{
get { return _dtvalue.ToString(); }
set { DateTime.TryParse(value, out _dtvalue); }
}
public string t
{
get { return _tvalue.ToString(); }
set { DateTime.TryParse(value, out _tvalue); }
}
public string v
{
get { return _vvalue.ToString(); }
set { int.TryParse(value, out _vvalue); }
}
}
Inside my program class, I've instantiated and set with the following:
DTVitem item = new DTVitem();
item.dt = "2012/01/01";
item.t = "04:04:04";
item.v = "455";
So I opted not to use a struct, but a class; or really an instance of the class.
A property can only have one type. If you want the property to be of type string, then you can implement it this way:
public partial class DTVitem
{
private DateTime _datevalue;
public string dt
{
get { return _datevalue.ToString(); }
set { DateTime.TryParse(value, out _datevalue) ;}
}
}
However, using TryParse() will mean that the setter will not throw an exception if the DateTime is invalid. If you want it to do this, use DateTime.Parse() instead.
public partial class DTVitem
{
private DateTime _datevalue;
public string dt
{
get { return _datevalue.ToString(); }
set { DateTime.TryParse(value, out _datevalue) ;}
}
}
You're just missing a type convertion in the get. _datevalue is a DateTime but your property's a string.
get { return _datevalue.ToString(); } //or .toShortDateString() or ToShorttimeString()
The get;set; must have the same type. Your get returns a datetime when it expects a string, hence the error.
just use an explicit method bool setDate(String datestring) and put your code there. You can return a bool from the tryparse to let you know if it was successful.
Other (design mostly) issues aside, just getting to the problem of returning _datevalue as string, you can simply do something like:
public string dt
{
get { return _datevalue.ToString(); }
set { if(!DateTime.TryParse(value, out _datevalue)) /* Error recovery!! */ ;}
}
>>> You may also want to check the docs for DateTime.ToString() and see what format you want to get your string in when accessing the property.
I'm using Dapper to map my entities to SQL Server CE. If I save a DateTime with Kind=Utc, when I read it back I get a DateTime with Kind=Unspecified, which leads to all kind of problems.
Example:
var f = new Foo { Id = 42, ModificationDate = DateTime.UtcNow };
Console.WriteLine("{0} ({1})", f.ModificationDate, f.ModificationDate.Kind);
connection.Execute("insert into Foo(Id, ModificationDate) values(#Id, #ModificationDate)", f);
var f2 = connection.Query<Foo>("select * from Foo where Id = #Id", f).Single();
Console.WriteLine("{0} ({1})", f2.ModificationDate, f2.ModificationDate.Kind);
This code gives the following output:
20/09/2012 10:04:16 (Utc)
20/09/2012 10:04:16 (Unspecified)
I know I should be using a DateTimeOffset, but unfortunately SQL CE has no support for this type.
Is there a workaround? Can I tell Dapper to assume that all dates have DateTimeKind.Utc? And more generally, what are my options to customize the mapping?
EDIT: My current workaround is to patch the dates after Dapper has materialized the result, but it kind of smells...
var results = _connection.Query<Foo>(sql, param).Select(PatchDate);
...
static Foo PatchDate(Foo f)
{
if (f.ModificationDate.Kind == DateTimeKind.Unspecified)
f.ModificationDate = DateTime.SpecifyKind(f.ModificationDate, DateTimeKind.Utc);
return f;
}
Adding this answer for anyone else who comes looking for a simple fix. This is possible now with the addition of SqlMapper.TypeHandler in Dapper.
Add this class to convert the value from the db to a datetime with the kind specified as UTC.
public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
{
public override void SetValue(IDbDataParameter parameter, DateTime value)
{
parameter.Value = value;
}
public override DateTime Parse(object value)
{
return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
}
}
Then in my Global.asax file of my Web API I add the type handler to dapper.
SqlMapper.AddTypeHandler(new DateTimeHandler());
If you need to ensure you are always inserting dates as UTC, then on the SetValue method you can use:
parameter.Value = DateTime.SpecifyKind(value, DateTimeKind.Utc);
Looked into the Dapper code. Unless mine was out of date, for value types like datetime (which is mapped to DbType.DateTime), dapper just does a simple cast from the IDataReader object.
Pseudo : yield return (DateTime)IDataReader.GetValue(0);
That's the specific case for Datetime out of a bunch of generic code and lambdas.
AFAIK, SQL datetime never stores the offset / timezone so the kind will always say "Unspecified" on any datetime you store and fetch.
So, to do it cleanly, you could touch dapper internals:
which is a pain as you'd have to touch a big IL generating method (the DataRow Deserializer) and put in an if case for DateTime.
OR
just put a setter on the DateTime props where UTC is an issue (which is kinda against POCO but is relatively sane):
class Foo
{
private DateTime _modificationDate;
public DateTime ModificationDate
{
get { return _modificationDate; }
set { _modificationDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); }
}
//Ifs optional? since it's always going to be a UTC date, and any DB call will return unspecified anyways
}
Just wanted to put my full solution here for seamlessly integrating DateTimeOffset / DateTimeOffset? fields/properties with a MySQL 5.7 database (which doesn't support DbType.DateTimeOffset) - based on #matt-jenkins answer above:
public static class DapperExtensions
{
class DateTimeOffsetTypeHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
{
switch (parameter.DbType)
{
case DbType.DateTime:
case DbType.DateTime2:
case DbType.AnsiString: // Seems to be some MySQL type mapping here
parameter.Value = value.UtcDateTime;
break;
case DbType.DateTimeOffset:
parameter.Value = value;
break;
default:
throw new InvalidOperationException("DateTimeOffset must be assigned to a DbType.DateTime SQL field.");
}
}
public override DateTimeOffset Parse(object value)
{
switch (value)
{
case DateTime time:
return new DateTimeOffset(DateTime.SpecifyKind(time, DateTimeKind.Utc), TimeSpan.Zero);
case DateTimeOffset dto:
return dto;
default:
throw new InvalidOperationException("Must be DateTime or DateTimeOffset object to be mapped.");
}
}
}
private static int DateTimeOffsetMapperInstalled = 0;
public static void InstallDateTimeOffsetMapper()
{
// Assumes SqlMapper.ResetTypeHandlers() is never called.
if (Interlocked.CompareExchange(ref DateTimeOffsetMapperInstalled, 1, 0) == 0)
{
// First remove the default type map between typeof(DateTimeOffset) => DbType.DateTimeOffset (not valid for MySQL)
SqlMapper.RemoveTypeMap(typeof(DateTimeOffset));
SqlMapper.RemoveTypeMap(typeof(DateTimeOffset?));
// This handles nullable value types automatically e.g. DateTimeOffset?
SqlMapper.AddTypeHandler(typeof(DateTimeOffset), new DateTimeOffsetTypeHandler());
}
}
}
If you are using Dapper from source (not nuget), you could tweak the code to always force DateTimeKind of UTC. A more configurable option might be to create a new attribute for DateTime property values that allow you to specify date time kind as a hint to dapper. Dapper could look for DateTime properties with this attribute and when found could use it to specify the DateTime kind during ORM mapping. This might be a nice feature for core dapper as you are not the only one with this issue :)
This question already has answers here:
Unit Testing: DateTime.Now
(22 answers)
Closed last year.
I have this method which is dependent on current date. It checks if today is Sun, Mon, Tue or Wed, then it gives 5 days of lead time for arrival of shipped items. If its Thur, Fri or Sat then it gives 6 days of lead time to account for the weekend.
private DateTime GetEstimatedArrivalDate()
{
DateTime estimatedDate;
if (DateTime.Now.DayOfWeek >= DayOfWeek.Thursday)
{
estimatedDate = DateTime.Now.Date.AddDays(6);
}
else
{
estimatedDate = DateTime.Now.Date.AddDays(5);
}
return estimatedDate;
}
The actual estimation logic is more complex. I have simplified it for the purpose of this question. My question is how do I write a unit test for something like this which depends on todays date?
You need to pass the current date in as a parameter:
private DateTime GetEstimatedArrivalDate(DateTime currentDate)
{
DateTime estimatedDate;
if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
{
estimatedDate = currentDate.AddDays(6);
}
else
{
estimatedDate = currentDate.AddDays(5);
}
return estimatedDate;
}
In real code you call it like this:
DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date);
Then you can test it as follows:
DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10));
DateTime expected = ...;
// etc...
Note that this also fixes a potential bug in your program where the date changes between consecutive calls to DateTime.Now.
Generally speaking, you'd want to abstract the method of obtaining the current date and time behind an interface, eg:
public interface IDateTimeProvider
{
DateTime Now { get; }
}
The real service would be:
public class DateTimeProvider: IDateTimeProvider
{
public DateTime Now
{
get
{
return DateTime.Now;
}
}
}
And a test service would be:
public class TestDateTimeProvider: IDateTimeProvider
{
private DateTime timeToProvide;
public TestDateTimeProvider(DateTime timeToProvide)
{
this.timeToProvide = timeToProvide;
}
public DateTime Now
{
get
{
return timeToProvide;
}
}
}
For services that require the current time, have them take an IDateTimeProvider as a dependency. For the real thing, pass a new DateTimeProvider(); when you're a component, pass in a new TestDateTimeProvider(timeToTestFor).
Make your class take an IClock parameter (via constructor or property)
interface IClock
{
DateTime Now { get; }
}
You can then use a fake implementation for testing
class FakeClock : IClock
{
DateTime Now { get; set }
}
and a real implementation the rest of the time.
class SystemClock : IClock
{
DateTime Now { get { return DateTime.Now; } }
}
I would suggest doing this as Mark suggests, but with the addition of a overloaded call for production use that takes no parameter and uses DateTime.Now
private DateTime GetEstimatedArrivalDate()
{
return GetEstimatedArrivalDate(DateTime.Now);
}
private DateTime GetEstimatedArrivalDate(DateTime currentDate)
{
DateTime estimatedDate;
if (currentDate.DayOfWeek >= DayOfWeek.Thursday)
{
estimatedDate = currentDate.AddDays(6);
}
else
{
estimatedDate = currentDate.AddDays(5);
}
return estimatedDate;
}
One "common" way of doing so is to "fake" the current system date (that can be done in several ways) and then test your code on "known" dates.
Another interesting way is to change your implementation slightly to:
private DateTime GetEstimatedArrivalDate()
{
return GetEstimatedArrivalDate(DateTime.Now);
}
private DateTime GetEstimatedArrivalDate(DateTime forDate)
{
DateTime estimatedDate;
if (forDate.DayOfWeek >= DayOfWeek.Thursday)
{
estimatedDate = forDate.Date.AddDays(6);
}
else
{
estimatedDate = forDate.Date.AddDays(5);
}
return estimatedDate;
}
And then use the method with a parameter to test on "immediate" dates.
Seems like there are a limited enough number of cases that you could test them each explicitly. The method depends on today's date, but the output depends only on the day of week, and every date has a day of week.
You could pass in a delegate that returns DateTime.Now during normal execution, and then in your test pass in another delegate that returns a fixed date, and assert your result based on that.
I'll give the controversial answer, don't test it.
The logic is trivial and it has zero dependencies, i believe in good code coverage but not when it increases complexity for no real gain.