2009-05-27 41 views
6

Tôi đang cố gắng kiểm tra phương thức thực thể Order gọi là AddItem và tôi đang cố gắng đảm bảo rằng các mục trùng lặp không thể được thêm vào. Dưới đây là một số mã ví dụ:Kiểm tra đơn vị Câu hỏi Setter riêng (C#)

[Test] 
public void ItemCannotBeAddedTwiceToOrder() 
{ 
    Order o = new Order(); 
    Item i = new Item("Bike"); 

    o.AddItem(i); 
    o.AddItem(i); 

    Assert.AreEqual(o.ItemCount, 1, "A duplicate item was added."); 
} 

public void AddItem(Item newItem) 
{ 
    if(!CheckForDuplicateItem(newItem)) 
     _items.Add(newItem); 
} 

public bool CheckForDuplicateItem(Item newItem) 
{ 
    foreach(Item i in _items) 
    { 
     if(i.Id == newItem.Id) 
      return true; 
    } 

    return false; 
} 

Vì vậy, đây là vấn đề của tôi: làm thế nào để tôi thiết Id setter tin Item mới trong phương pháp thử nghiệm để các phương pháp CheckForDuplicateItem sẽ làm việc? Tôi không muốn biến thành viên đó thành công để thực hành mã hóa tốt, tôi đoán vậy. Tôi chỉ là ngu ngốc và cần phải thực hiện các mục thực thể có một setter Id công cộng? Hay tôi cần sử dụng sự phản chiếu? Cảm ơn

Lưu ý - Tôi đang sử dụng NHibernate để kiên trì

Trả lời

8

Tôi thường sử dụng phản ánh cho mục đích này. Một cái gì đó như thế này sẽ hoạt động:

typeof(Item).GetProperty("Id").SetValue(i, 1, null); 

trong đó 1 là id mà bạn muốn đặt cho thể hiện NewItem.

Theo kinh nghiệm của tôi, bạn hiếm khi cần đặt Id, vì vậy tốt hơn hết là chỉ để rời khỏi thiết lập riêng tư. Trong một vài trường hợp bạn cần đặt Id cho mục đích thử nghiệm, chỉ cần sử dụng Reflection.

+0

Thanks a lot. Tôi sẽ thử. – CalebHC

7

Vì bạn đang kiểm tra hành vi của Đơn đặt hàng, bạn có thể sử dụng các đối tượng giả làm mục của nó. Sử dụng các đối tượng giả, bạn có thể xác định các xác nhận của bạn về những gì sẽ xảy ra với các đối tượng giả của bạn và kiểm tra chúng. Trong trường hợp này, bạn có thể xác định hai đối tượng giả cho mỗi mục và mong rằng trình lấy id sẽ được gọi và sẽ trả về một giá trị duy nhất. Sau đó, bạn có thể kiểm tra hành vi Order và kiểm tra xem id getter của item có được gọi là bạn không kỳ vọng. Tôi khuyên bạn nên sử dụng Rhino Mocks bởi Ayende

+0

Điểm tốt. Tôi sẽ nhìn vào chế nhạo. Tôi đã nghe rất nhiều điều tốt đẹp về Rhino Mocks. – CalebHC

0

Một giải pháp khác là làm cho các thành viên riêng có thể truy cập được từ lớp và hiển thị thành viên trong lớp dẫn xuất. Đây là khá nhiều chi phí để thử nghiệm và Visual Studio chỉ có build-in support for private methods.

0

Tôi nghĩ bạn có thể đang bỏ lỡ điểm ở đây. Bạn có tránh nhiều bổ sung vì bạn không muốn nhiều cuộc gọi đến DB không? Tôi nghĩ NHibernate mang đến cho bạn điều đó miễn phí. Ngoài ra, bạn có nên sử dụng Bộ không? Các hàm ý cho người gọi là một mục có thể hoặc không thể được thêm vào là gì?

Nếu không có sự cố liên tục, bạn chỉ có thể thêm hai mục riêng biệt với cùng một ID và xác nhận rằng bạn chỉ có một mục đầu tiên. Phải có một số cách để phát hiện các vật phẩm nào theo thứ tự, hoặc sẽ không có điểm nào khi thêm chúng vào.

3

Trong khi câu trả lời của Praveen là đúng và không nghi ngờ gì về cách sử dụng đơn lẻ, sử dụng điều này trong các thử nghiệm trên một mô hình miền mạnh hơn và hơn. Vì vậy, tôi bọc nó trong một phương pháp mở rộng cho phép bạn điều này kiểu cuộc gọi an toàn để thiết lập một giá trị:

var classWithPrivateSetters= new ClassWithPrivateSetters(); 
classWithPrivateSetters.SetPrivate(cwps => cwps.Number, 42); 

Drop này vào lắp ráp thử nghiệm của bạn và bạn tốt để đi

public static class PrivateSetterCaller 
{ 
    public static void SetPrivate<T,TValue>(this T instance, Expression<Func<T,TValue>> propertyExpression, TValue value) 
    { 
     instance.GetType().GetProperty(GetName(propertyExpression)).SetValue(instance, value, null); 
    } 

    private static string GetName<T, TValue>(Expression<Func<T, TValue>> exp) 
    { 
     MemberExpression body = exp.Body as MemberExpression; 

     if (body == null) 
     { 
      UnaryExpression ubody = (UnaryExpression)exp.Body; 
      body = ubody.Operand as MemberExpression; 
     } 

     return body.Member.Name; 
    } 
}