ฉันไม่คิดว่าตัวเองเป็นผู้เชี่ยวชาญ DDD แต่ในฐานะสถาปนิกโซลูชันพยายามใช้แนวทางปฏิบัติที่ดีที่สุดเท่าที่จะทำได้ ฉันรู้ว่ามีการถกเถียงกันอย่างมากมายเกี่ยวกับ "สไตล์" setter ของมือโปรและผู้ต่อต้านใน DDD และฉันสามารถเห็นการโต้แย้งทั้งสองด้าน ปัญหาของฉันคือฉันทำงานเป็นทีมที่มีทักษะความรู้และประสบการณ์ที่หลากหลายซึ่งหมายความว่าฉันไม่สามารถไว้วางใจได้ว่านักพัฒนาทุกคนจะทำสิ่งที่ "ถูกต้อง" ตัวอย่างเช่นหากวัตถุโดเมนของเราได้รับการออกแบบเพื่อให้การเปลี่ยนแปลงสถานะภายในของวัตถุดำเนินการโดยวิธีการ แต่ให้ผู้ตั้งค่าทรัพย์สินสาธารณะบางคนจะหลีกเลี่ยงไม่ได้ตั้งค่าคุณสมบัติแทนการเรียกวิธีการ ใช้ตัวอย่างนี้:
public class MyClass
{
public Boolean IsPublished
{
get { return PublishDate != null; }
}
public DateTime? PublishDate { get; set; }
public void Publish()
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
PublishDate = DateTime.Today;
Raise(new PublishedEvent());
}
}
วิธีการแก้ปัญหาของฉันคือการทำให้ตัวตั้งค่าคุณสมบัติเป็นส่วนตัวซึ่งเป็นไปได้เพราะ ORM ที่เราใช้ในการทำให้วัตถุชุ่มชื้นนั้นใช้การสะท้อนเพื่อให้สามารถเข้าถึงตัวตั้งค่าส่วนตัวได้ อย่างไรก็ตามสิ่งนี้นำเสนอปัญหาเมื่อพยายามเขียนการทดสอบหน่วย ตัวอย่างเช่นเมื่อฉันต้องการเขียนการทดสอบหน่วยที่ตรวจสอบความต้องการที่เราไม่สามารถเผยแพร่ซ้ำได้ฉันต้องระบุว่าวัตถุนั้นได้รับการเผยแพร่แล้ว แน่นอนฉันสามารถทำได้โดยโทร Publish สองครั้ง แต่จากการทดสอบของฉันสมมติว่า Publish ได้รับการติดตั้งอย่างถูกต้องสำหรับการโทรครั้งแรก ดูเหมือนว่าจะส่งกลิ่นเล็กน้อย
ให้สถานการณ์เป็นจริงมากขึ้นด้วยรหัสต่อไปนี้:
public class Document
{
public Document(String title)
{
if (String.IsNullOrWhiteSpace(title))
throw new ArgumentException("title");
Title = title;
}
public String ApprovedBy { get; private set; }
public DateTime? ApprovedOn { get; private set; }
public Boolean IsApproved { get; private set; }
public Boolean IsPublished { get; private set; }
public String PublishedBy { get; private set; }
public DateTime? PublishedOn { get; private set; }
public String Title { get; private set; }
public void Approve(String by)
{
if (IsApproved)
throw new InvalidOperationException("Already approved.");
ApprovedBy = by;
ApprovedOn = DateTime.Today;
IsApproved = true;
Raise(new ApprovedEvent(Title));
}
public void Publish(String by)
{
if (IsPublished)
throw new InvalidOperationException("Already published.");
if (!IsApproved)
throw new InvalidOperationException("Cannot publish until approved.");
PublishedBy = by;
PublishedOn = DateTime.Today;
IsPublished = true;
Raise(new PublishedEvent(Title));
}
}
ฉันต้องการเขียนการทดสอบหน่วยที่ตรวจสอบ:
- ฉันไม่สามารถเผยแพร่ได้หากเอกสารได้รับการอนุมัติแล้ว
- ฉันไม่สามารถเผยแพร่เอกสารได้อีกครั้ง
- เมื่อเผยแพร่แล้วค่าที่ได้รับการเผยแพร่โดย PublishingBy และจะถูกตั้งค่าอย่างเหมาะสม
- เมื่อ publised ที่เผยแพร่แล้ว Event จะเพิ่มขึ้น
โดยไม่ต้องเข้าถึงตัวตั้งค่าฉันไม่สามารถนำวัตถุเข้าสู่สถานะที่จำเป็นในการทำการทดสอบ การเปิดการเข้าถึงตัวตั้งค่าเอาชนะวัตถุประสงค์ในการป้องกันการเข้าถึง
คุณมีวิธีแก้ (ง) ปัญหานี้อย่างไร?