讓我們考慮下面的例子:
internal class Meeting
{
public int Id { get; set; }
}
internal class DailyRoomReservation
{
private ISet<Meeting> _meetings { get; set; } = new HashSet<Meeting>();
internal void ScheduleMeeting(Meeting meeting)
{
if (_meetings.Contains(meeting)) throw new InvalidOperationException();
_meetings.Add(meeting);
}
}
假設這DailyRoomReservation是我的聚合根(為了簡單起見,我故意省略了大部分業務邏輯),我應該如何測驗它?僅公開聚合的命令方法(CQS 術語)是已知的良好做法,尤其是在大圖使用 CQRS 時。此外,我沒有公開該_meetings屬性的業務需要(測驗目的當然不是這樣做的好理由)。我寫了以下測驗:
[Test]
internal void ScheduleNewMeeting_ShouldSucceed()
{
var uniqueMeeting = new Meeting() { Id = 1};
var dailyRoomReservation = new DailyRoomReservation();
dailyRoomReservation.ScheduleMeeting(uniqueMeeting);
}
[Test]
internal void ScheduleSameMeetingTwice_ShouldFail()
{
var meeting = new Meeting() { Id = 1};
var dailyRoomReservation = new DailyRoomReservation();
dailyRoomReservation.ScheduleMeeting(meeting);
Action scheduleMeeting = () => dailyRoomReservation.ScheduleMeeting(meeting);
scheduleMeeting.Should().ThrowExactly<InvalidOperationException>();
}
他們作業得很好,但是我仍然無法驗證是否真的添加了會議。如何改進我的方法?
uj5u.com熱心網友回復:
啟發式:只寫域物體實際上并不提供任何商業價值。
如果您將資訊放入域物體中,您這樣做的目的是期望從中產生的資訊可能會發生一些變化。
因此,我們測驗的基本結構是我們獲得一個物體的實體,我們向它發送一系列命令,然后我們測量出來的資訊。如果測量符合某個預定規范(換句話說,如果斷言通過),我們的域物體通過測驗。
我們至少可以通過四種不同的方式來獲取資訊。
首先,我們實際上可以進入并查看內部資料模型。在某些情況下這很好(通常是一次性測驗,也就是腳手架,我們不希望將其兼作檔案)。
其次,我們可以查詢物體以獲取資訊 - 當您有一個預期支持該查詢作為其域表示的一部分的物體時非常適合。
第三,我們可以竊聽該物體發送給我們代碼其他部分的訊息,并以這種方式捕獲資訊的副本。這是tell-dont-ask設計中的一種常見方法,我們使用測驗替身/替代來捕獲我們想要評估的資訊。
第四,如果我們期望持久存盤域資料,我們可以“存盤”物體,然后(a)檢查其持久表示或(b)將該表示加載到“讀取模型”中并進行查詢。
在將測驗和可觀察性視為首要問題的背景關系中,我們當然會實作一個查詢方法來允許訪問我們想要驗證的資訊的副本。我們物體的實作包含這樣一個方法這一事實并不一定意味著該方法是已發布介面的一部分。
在這個特定示例中,您可以使用“它會拋出嗎?”作為您的測量值。我希望看到至少四次測驗
- 添加一個會議不會拋出
- 添加具有不同識別符號的兩個會議不會拋出
- 兩次添加同一個會議確實會引發
- 添加具有相同識別符號的兩個會議確實會引發
但是在我們希望將重復會議的安排視為無操作的領域中,這種測量并不令人滿意,我們需要撰寫測驗來檢測其他一些差異。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/406519.html
標籤:
上一篇:Angular10/.Net4.8請求標頭更改為駝峰式
下一篇:C#如何區分不同的委托簽名?
