问题描述
在使用XUnit编写某些单元之前,直到某些时候我碰到了一些令人惊讶的事情:
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 = "[email protected]"
}
[<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)
尤其令人惊奇的是,考虑到Assert
使用的重载为:
It seems surprising especially since considering that the overload used by Assert
is:
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual)
其中指出:
为什么认为它们不同,为什么Assert.Equal
会引起System.NullReferenceException
?
Why are they considered different, and why does Assert.Equal
raise a System.NullReferenceException
?
似乎
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
事实证明,event
的字段之一是null
,而不是event
本身.
It turns out one of the fields of event
was null
, but not event
itself.
推荐答案
问题出在测试/[<Fact>]
上方定义的id
和contact
中:
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 = "[email protected]"
}
[<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)
问题是,当独立运行测试时,id
和contact
未初始化,因此,即使event
不是null
,接触也是null
(id
是Guid
一个struct
它仍然具有值).
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).
由于F#具有结构相等性,因此如果未初始化该字段之一,则足以具有一个null
字段,以使Assert
在其实现的某个时刻失败.
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:
- 直接在单元测试主体中定义这些变量.
- 从单元测试主体中产生这些值的定义方法
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 = "[email protected]"
}
[<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.
也许值得再问一个问题,为什么会这样.从某种意义上说,这是令人惊讶的,如果可以定义一个函数并返回与那些变量几乎相同的东西,则意味着let也已正确编译,那么为什么变量不是这种情况?
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?
这篇关于F#:为什么这两个集合不相等?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!