问题
Was writing some units using XUnit until that at some points I bumped into something surprising:
let id = Guid.Empty
let contact = {
Name = {
FirstName = "Marcel"
MiddleInitial = None
LastName = "Patulacci"
}
DateOfBith = new DateTime(1850, 12, 25)
Address = {
Address1 = "41 av 8 Mai 1945"
Address2 = None
City = "Sarcelles"
State = None
Zip = "95200"
}
PhoneNumber = {
DialOutCode = 33
LocalNumber = "766030703"
}
Email = "marcel.patulacci@outlook.com"
}
[<Fact>]
let ``Open an account...``() =
let event = Event.AccountOpened({
AccountId = id
Contact = contact
})
let a = [event]
let b = seq { yield event }
Assert.Equal(a, b)
System.NullReferenceException
: Object reference not set to an instance of an object.
It seems surprising especially since considering that the overload used by Assert
is:
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual)
Which states that:
Verifies that two sequences are equivalent, using a default comparer.
Why are they considered different, and why does Assert.Equal
raise a System.NullReferenceException
?
[EDIT]
System.NullReferenceException
: Object reference not set to an instance of an object. atDomain.Events.AccountOpenedEvent.Equals(Object obj, IEqualityComparer comp)
atDomain.Events.Event.Equals(Object obj, IEqualityComparer comp)
Seems
type PersonalName = {
FirstName: string;
MiddleInitial: string option;
LastName: string;
}
type Address = {
Address1: string;
Address2: string option ;
City: string;
State: string option;
Zip: string;
}
type PhoneNumber = {
DialOutCode : int;
LocalNumber: string
}
type Contact = {
Name: PersonalName;
DateOfBith: DateTime
Email: string;
Address: Address;
PhoneNumber: PhoneNumber
}
type AccountOpenedEvent = {
AccountId: Guid
Contact: Contact
}
type Event =
| AccountOpened of AccountOpenedEvent
It turns out one of the fields of event
was null
, but not event
itself.
回答1:
The problem resided in the id
and contact
that were defined right above the test / [<Fact>]
:
let id = Guid.Empty
let contact = {
Name = {
FirstName = "Marcel"
MiddleInitial = None
LastName = "Patulacci"
}
DateOfBith = new DateTime(1850, 12, 25)
Address = {
Address1 = "41 av 8 Mai 1945"
Address2 = None
City = "Sarcelles"
State = None
Zip = "95200"
}
PhoneNumber = {
DialOutCode = 33
LocalNumber = "766030703"
}
Email = "marcel.patulacci@outlook.com"
}
[<Fact>]
let ``Open an account...``() =
let event = Event.AccountOpened({
AccountId = id
Contact = contact
})
let a = [event]
let b = seq { yield event }
Assert.Equal(a, b)
The thing is when running the test independently the id
and contact
are not initialized, hence even though event
was not null
, contact was null
(id
being a Guid
aka a struct
it has a value anyway).
Since F# works with structural equality, if one of the field is not initialized it was enough to have a field null
to make the Assert
failed at some point in its implementation.
There are a few solutions / workarounds:
- Defining those variables directly in the unit test body.
- Defining methods which produce those values out of the unit test body
let getId() = Guid.Empty
let getContact() = {
Name = {
FirstName = "Marcel"
MiddleInitial = None
LastName = "Patulacci"
}
DateOfBith = new DateTime(1850, 12, 25)
Address = {
Address1 = "41 av 8 Mai 1945"
Address2 = None
City = "Sarcelles"
State = None
Zip = "95200"
}
PhoneNumber = {
DialOutCode = 33
LocalNumber = "766030703"
}
Email = "marcel.patulacci@outlook.com"
}
[<Fact>]
let ``Open an account...``() =
let id = getId()
let contact = getContact()
let event = Event.AccountOpened({
AccountId = id
Contact = contact
})
let a = [event]
let b = seq { yield event }
Assert.Equal(a, b)
While those workarounds work, I am surprised that the variables declared right above the unit test function are not considered when the test is running / and are uninitialized.
It might worth to shoot another question about why this is the case. This is surprising in the sense that if a function can be defined and returning pretty much the same thing as those variables it means that let is also properly compiled, so why this is not the case with the variables?
来源:https://stackoverflow.com/questions/56484369/f-why-those-two-collections-are-not-equal