2009-06-08 27 views
5

Câu hỏiTrong TDD và DDD, làm thế nào để bạn xử lý các thuộc tính chỉ đọc trong hàng giả?

Làm cách nào để bạn xử lý trường chỉ đọc khi tạo hàng giả?

nền

Tôi đang ở giai đoạn bắt đầu của việc sử dụng ASP.Net MVC và tôi sử dụng thể thao hàng Steven Sanderson và Dinner Nerd Scott Gu làm ví dụ. Một vấn đề nhỏ mà tôi vừa mới đánh là cách làm việc với các thuộc tính chỉ đọc khi thực hiện các lệnh giả mạo. Tôi đang sử dụng LINQToSQL.

giao diện của tôi là:

public interface IPersonRespository 
{ 
    Person GetPerson(int id); 
} 

và giả của tôi trở nên

public class FakePersonRepository 
{ 
    public Person GetPerson(int id) 
    { 
     return new Person {id="EMP12345", name="John Doe", age=47, ssn=123-45-6789, totalDrWhoEpisodesWatched=42}; 
    } 
} 

Dưới đây là vấn đề của tôi. Các trường id, ssn và totalDrWhoEpisodesWatched là chỉ đọc, vì vậy mã trên sẽ không thực sự hoạt động. Tuy nhiên, tôi không nhận ra cách tạo một người mới giả và thiết lập thuộc tính chỉ đọc. Tôi chắc chắn có một giải pháp, nhưng tôi chưa từng tìm thấy nó trong các tìm kiếm của tôi.

Cập nhật: Thừa kế + Thuộc tính ẩn chứa làm giải pháp tiềm năng?

Tôi chưa quyết định giải pháp vững chắc cho vấn đề. Tôi không thích khái niệm sửa đổi các lớp Domain của tôi với mục đích tạo ra hàng giả. Đối với tôi, việc thêm đánh dấu vào các lớp miền để thực hiện kiểm thử là một dạng ghép nối bổ sung để thực hiện kiểm thử của bạn. Bây giờ tôi đang điều tra một khả năng khác, đó là tạo ra một lớp FakePerson, mà kế thừa từ Person, nhưng ẩn các thuộc tính với các thuộc tính read-write mới.

public class FakePerson: Person 
{ 
    public new int age { get; set; } 
    public new string ssn { get; set; } 
    public new int totalDrWhoEpisodesWatched { get; set; } 
} 

Cho đến nay, giải pháp này là cách tôi nghiêng. Nó phá vỡ Nguyên tắc thay thế Liskov, tuy nhiên điều đó không làm tôi khó chịu nhiều trong một dự án thử nghiệm. Tôi rất vui khi nghe bất kỳ lời chỉ trích và/hoặc phản hồi nào về vấn đề này như một giải pháp.

Winner: Mock Khung

Moq dường như thực hiện công việc. Giải pháp cuối cùng của tôi về việc ẩn thuộc tính thông qua thừa kế, trên thực tế, công việc, tuy nhiên bằng cách sử dụng Moq, tôi nhận được một tập hợp các chức năng tiêu chuẩn được duy trì nhiều hơn. Tôi giả định rằng các khuôn khổ giả khác có chức năng này, nhưng tôi chưa kiểm tra. Moq được cho là đơn giản hơn cho việc bắt đầu viết mock, mà tôi chắc chắn là ngay bây giờ.

+0

Tại sao nó thiết lập để được readonly? –

+0

Nó được đặt thành chỉ đọc vì không có người dùng nào của miền có quyền sửa đổi thuộc tính. Có thể vì một số lý do, nhưng thường là do ứng dụng không có quyền sửa đổi trường vì đó là trường tính toán/được tạo tự động hoặc do chính sách bảo mật của cơ sở dữ liệu. – John

+3

Về chủ đề không liên quan chút nào, tôi khuyên bạn nên đổi tên thuộc tính thành PascalCase để tuân thủ các quy ước đặt tên .NET. http://msdn.microsoft.com/en-us/library/ms229043(loband).aspx –

Trả lời

6

Xem xét chế nhạo loại Người trong thử nghiệm của bạn. Ví dụ sử dụng Moq:

var mock = new Mock<Person>(); 
mock.SetupGet(p => p.id).Returns("EMP12345"); 
mock.SetupGet(p => p.ssn).Returns("123-45-6789"); 
mock.SetupGet(p => p.totalDrWhoEpisodesWatched).Returns(42); 
return mock.Object; 

Nếu không, hãy thử tìm hiểu cách LINQ to SQL đặt những thuộc tính chỉ đọc đó.

EDIT: Nếu bạn cố gắng ở trên và Moq ném một ArgumentException trong cuộc gọi SetupGet với thông điệp "thiết lập không hợp lệ trên một thành viên phi overridable: p => p.id", sau đó bạn cần phải đánh dấu thuộc tính là virtual. Điều này sẽ cần phải được thực hiện cho mỗi thuộc tính có getter bạn muốn ghi đè lên.

Trong LINQ to SQL, điều này có thể được thực hiện trong HOẶC thiết kế bằng cách chọn tài sản, sau đó trong cửa sổ Properties thiết Inheritance Modifier để ảo.

+0

Có thể moq bỏ qua các đạo cụ chỉ đọc không? Tôi nhớ rằng tôi đã có vấn đề với tê giác tê giác. :/ –

+0

Bạn đang đề cập đến "các trường" chỉ đọc hay các thuộc tính không có trình cài đặt có thể truy cập công khai? Trong trường hợp trước đây tôi không nghĩ rằng Moq có thể giúp đỡ. Trong trường hợp thứ hai, các setters không quan trọng - Moq chỉ ghi đè lên getter. – mvr

+0

Thuộc tính chỉ đọc (nghĩa là thuộc tính có bộ). LINQ to SQL đặt biến riêng trong lớp Person, trong ví dụ này sẽ là _id, _ssn và _totalDrWhoEpisodesWatched. – John

1

Bạn chỉ có thể đặt thuộc tính chỉ đọc trong hàm tạo của lớp. Đối tượng Person sẽ có một hàm tạo chấp nhận id, ssn và totalDrWhoEpisodesWatched. Tất nhiên, nếu đây là một đối tượng được tạo ra linqtosql, bạn có thể có vấn đề sửa đổi rằng mã được tự động tạo ra.

Bạn có thể xem xét sử dụng đối tượng được ánh xạ để hiển thị trong kho lưu trữ của mình ... vì vậy bạn sẽ không bao giờ thực sự phải sử dụng đối tượng linqtosql làm mô hình của mình.

+0

@ Joel- Bạn có thấy chi phí của việc sử dụng một mô hình POCO hoàn toàn xứng đáng với nỗ lực thêm theo yêu cầu của ánh xạ kép không? – RichardOD

+0

Tôi không thích ý tưởng thêm ssn và totalDrWhoEpisodesWatched vào hàm tạo. Thêm các tham số bổ sung không thực sự cần thiết trong chương trình đang chạy chỉ để thực hiện kiểm tra có vẻ ngược lại với thiết kế API tốt, bởi vì nó có nghĩa là công khai một phương thức mà người tiêu dùng không nên sử dụng (trừ người tiêu dùng thử nghiệm). Bạn có ý nghĩa gì với một "đối tượng được ánh xạ"? – John

+0

@RichardOD, đôi khi :-) @John, bởi đối tượng được ánh xạ, tôi muốn sử dụng một đối tượng mà bạn đã mã hóa chính mình (thay vì dựa vào lớp được tạo tự động mà linq2sql cung cấp). Vì vậy, khi bạn chọn từ kho dữ liệu của bạn, bạn sẽ làm (chọn MyPerson mới() {...}) và thiết lập các thuộc tính của bạn ở đó. Điều này cho phép bạn tránh sự phụ thuộc vào một lớp được tạo tự động mà có thể hoặc không thể thay đổi trong tương lai. –

1

Trong .NET, bạn có thể đánh dấu các bộ định cư là "nội bộ" và sử dụng thuộc tính assembly InternalsVisibleTo để hiển thị nội bộ cho cụm kiểm tra của bạn. Bằng cách đó, người định cư của bạn sẽ không được công khai, nhưng bạn vẫn có thể truy cập chúng.

lưu ý: mặc dù câu hỏi không được gắn thẻ.NET, tôi giả sử nó dựa trên việc bạn sử dụng cú pháp khởi tạo đối tượng. Nếu giả định của tôi sai, đề xuất này không áp dụng (trừ khi ngôn ngữ bạn đang sử dụng có tính năng tương đương, tất nhiên).

+0

Tôi đã không đánh dấu nó. Net, tuy nhiên tôi nhận thấy rằng các đề cập của ASP.net và LinqToSQL sẽ cho rằng đi. Cảm ơn. – John

0

Nếu đó là để kiểm tra - hãy cân nhắc sử dụng sự phản chiếu. Điều đó sẽ không liên quan đến rối tung xung quanh mô hình miền của bạn.

Ví dụ - tôi có lớp FactoryBase, sử dụng sự phản chiếu để đặt prop cần thiết bằng biểu thức lambda thông qua các tham số (như this). Các công trình như một sự quyến rũ - tạo ra nhà máy mới đơn giản như xác định loại kho lưu trữ và dữ liệu thực thể mặc định.

+0

Câu trả lời là hấp dẫn, nhưng tôi không thấy cách giải quyết vấn đề mà tôi đã hỏi, đó là cách xử lý các thuộc tính chỉ đọc trong hàng giả. Foo có những người định cư cho tất cả 3 tài sản (Bar, Baz và Bling). Bạn sẽ làm gì nếu BAZ chỉ có một getter? – John

+0

Phản ánh có thể xử lý điều đó. Có một số đối tượng miền với setters được bảo vệ và riêng tư quá. –

0

Tôi cũng sử dụng Moq. Tôi thích nó và nó hoạt động rất tốt. Nhưng, trước khi tôi bắt đầu sử dụng Moq, tôi đã viết nhiều giả. Đây là cách tôi sẽ giải quyết vấn đề bằng cách sử dụng hàng giả.

Vì giả mạo có thể có các phương thức bổ sung mà triển khai "sản xuất" không có, tôi sẽ thêm một vài phương thức bổ sung vào việc triển khai giả để xử lý việc thiết lập phần chỉ đọc.

Như thế này:

public class FakePersonRepository : IPersonRespository 
{ 
    private IDictionary<int, Person> _people = new Dictionary<int, Person>(); 

    public Person GetPerson(int id) // Interface Implementation 
    { 
     return _people(id); 
    } 

    public void SetPerson(int id, Person person) // Not part of interface 
    { 
     _people.Add(id, person); 
    } 

} 
Các vấn đề liên quan