2010-07-30 43 views
5

Bất kỳ ai cũng có thể hướng dẫn tôi phương tiện được đề xuất để thử nghiệm một trường riêng tư trong một lớp được sửa đổi thông qua phương thức công khai. Tôi đã đọc rất nhiều ý kiến ​​từ những người cho rằng thử nghiệm các thành viên tư nhân không được thông báo vì họ đang trong quá trình thực hiện, tuy nhiên kịch bản này dường như khác với hầu hết các câu trả lời khác.Cách kiểm tra các trường riêng được sửa đổi thông qua các phương thức công cộng

Tôi đã suy nghĩ về việc tạo trường riêng tư được bảo vệ và tạo một lớp con kiểm tra để hiển thị trường nhưng nếu tôi không thể sửa đổi nội bộ của lớp thì sao?

Trong mã mẫu bên dưới thành viên riêng để kiểm tra sẽ là _values ​​là bộ sưu tập chỉ ghi nhận giá trị mới thông qua AddValue().

public class Sample 
{ 

    private Dictionary<string, string> _values; 
    private DateTime _created; 

    public Sample() 
    { 
     _values = new Dictionary<string, string>(); 
     _created = DateTime.Now; 
    } 

    public void AddValue(string key, string value) 
    { 
     _values.Add(key, value); 
    } 
} 
+0

Ví dụ này "khác" như thế nào? Lớp học cung cấp những chức năng nào mà bạn cần kiểm tra? –

+0

@Rex Tôi không chắc chắn nó là khác nhau, tôi nghĩ rằng nó "có vẻ" khác nhau. Trong trường hợp này, phần tử bên trong chỉ đơn giản là một vùng lưu trữ. Tôi muốn kiểm tra các phương thức công cộng đang hoạt động chính xác, tuy nhiên cách duy nhất để làm điều này là kiểm tra trường riêng. (lớp thực sự sẽ có logic phức tạp hơn trong phương pháp AddValue) – WDuffy

Trả lời

2

Tôi nghĩ rằng đây sẽ là một ví dụ trong đó tiêm phụ thuộc có thể hữu ích.

Điều đang xảy ra ở đây là bạn muốn kiểm tra xem một đối tượng bên trong (từ điển _values) đã được cập nhật chính xác chưa bằng một cuộc gọi đến AddValue.Bạn có thể đạt được điều này bằng cách tiêm một từ điển giả vào bài kiểm tra của bạn.

Điều này có thể được thực hiện, ví dụ: như sau. Trước tiên, bạn sẽ phải thay đổi lớp Sample của bạn một chút:

public class Sample 
{ 
    private IDictionary<string, string> _values = new Dictionary<string, string>(); 

    protected virtual IDictionary<string, string> GetDictionary() 
    { 
     return this._values; 
    } 

    public void AddValue(string key, string value) 
    { 
     GetDictionary().Add(key, value); 
     // ^^^ 
     // notice this! 
    } 
} 

này bây giờ cho phép bạn thay thế các từ điển mặc định với nhau (mà bạn có thể quan sát trong thiết lập thử nghiệm của bạn) bằng cách bắt nguồn từ lớp Sample của bạn và tiêm một cuốn từ điển mock bằng cách ghi đè các phương pháp InitializeDictionary:

// this derived class is only needed in your test project: 
internal class SampleTest : Sample 
{ 
    public SampleTest(IDictionary<string, string> dictionaryToUse) 
    { 
     this._dictionaryToUse = dictionaryToUse; 
    } 

    private IDictionary<string, string> _dictionaryToUse; 

    protected override IDictionary<string, string> GetDictionary() 
    { 
     return this._dictionaryToUse; 
    } 
} 

trong thiết lập thử nghiệm của bạn, bạn có thể kiểm tra tại lớp SampleTest này thay vì lớp Sample của bạn. Điều này nên được OK vì lớp dẫn xuất là giống hệt nhau ngoại trừ mà nó cho phép bạn chỉ định từ điển mà nó sẽ sử dụng trong nội bộ. Một thử nghiệm đơn vị để kiểm tra AddValue bây giờ có thể trông như thế này:

[Test] 
public void AddValue_addSomething_DictionaryHasOneAdditionalEntry() 
{ 
    var mockDictionary = new Dictionary<string, string>(); 
    var sample = new SampleTest(mockDictionary); 
    var oldCount = mockDictionary.Count; 

    sample.AddValue(...); 

    Assert.AreEqual(oldCount + 1, mockDictionary.Count); 
} 

Disclaimer: Tôi không phải là một chuyên gia về kiểm tra đơn vị, vì vậy ví dụ của tôi có thể có những thiếu sót hoặc thậm chí là cách quá phức tạp . Ý định của tôi chỉ đơn thuần là chứng minh rằng bạn có thể kiểm tra các thuộc tính nội bộ của một lớp nếu bạn thiết kế lớp của mình theo cách có thể kiểm tra hợp lý - ví dụ: bằng cách cho phép các phương tiện tiêm phụ thuộc.

+0

Có stakx, tôi thích nó. – WDuffy

+0

Đó là cách tôi sẽ làm. – xpmatteo

4

Bạn vẫn không cần kiểm tra các biến riêng tư của mình. Bạn kiểm tra giao diện của bạn. Trong trường hợp này, tôi có thể thêm một tài sản Count và sử dụng cho một số thử nghiệm (hoặc một số thứ dọc theo các dòng đó)

+0

Có lẽ tôi đang suy nghĩ về nó nhiều. Việc thêm một thuộc tính Count đơn giản sẽ thực sự hoạt động tốt. – WDuffy

2

Một tùy chọn bạn có, nếu bạn muốn xác minh rằng _values chứa những gì bạn mong đợi sau khi bạn làm một cuộc gọi đến Sample.AddValue sẽ được thay đổi:

private Dictionary<string, string> _values; 

để có

internal Dictionary<string, string> _values; 

Và sau đó thêm một InternalsVisibleTo attribute đến AssemblyInfo.cs cho dự án của bạn, tham khảo dự án thử nghiệm của bạn. Sau đó, trường này sẽ hiển thị trường _values ​​cho dự án thử nghiệm của bạn.

Cách xa lý tưởng, bởi vì bạn muốn "thử nghiệm" chi tiết triển khai nội bộ, nhưng nếu đó là hoặc không có gì, đó là điểm khởi đầu!

+0

Ý tưởng thú vị Rob, yucky, nhưng giống như bạn nói đó là một điểm khởi đầu – WDuffy

+0

Đây là cách tôi đã luôn luôn nhìn thấy nó được thực hiện. –

2

Tôi nghĩ ý tưởng trong các bài kiểm tra đơn vị là kiểm tra hành vi của một đối tượng bằng bề mặt công cộng của nó, chứ không phải bởi việc thực hiện nội bộ của nó. Nói cách khác, bạn không nên truy cập vào _values trong bài kiểm tra của mình; thay vào đó, bạn nên gọi phương thức công khai AddValue() để thêm một vài khóa/giá trị và sau đó là một số phương pháp công khai khác, ví dụ: GetKeys() hoặc thứ gì đó, để lấy lại thông tin. Sau đó, thử nghiệm đơn vị của bạn nên kiểm tra xem thông tin đó có chính xác không cho thông tin đã đi vào.

Lý do chính là kiểm tra đơn vị không nên đưa ra bất kỳ giả định nào về chi tiết triển khai. Hãy tưởng tượng bạn cần thay đổi Dictionary<> thành SortedDictionary<> sau đó, vì bất kỳ lý do gì, hoặc bạn đột nhiên cần hai từ điển riêng biệt. Bạn không cần phải thực hiện bất kỳ thay đổi nào đối với thử nghiệm đơn vị để tính năng này hoạt động; bạn sẽ có thể thay đổi triển khai nội bộ và sau đó xác minh tính chính xác của nó bằng cách sử dụng cùng một bài kiểm tra đơn vị mà bạn đã có.

+0

Không chắc chắn lý do tại sao bạn đã bỏ phiếu Timiwi, nhưng từ điển nội bộ không thể công khai, nó phải là riêng tư và chỉ viết. – WDuffy

+0

@WDuffy: Không có gì trong câu trả lời của tôi cho thấy rằng nó sẽ được công khai. Nó không rõ ràng những gì bạn có nghĩa là bởi "chỉ ghi". Nếu bạn thực sự chỉ bao giờ viết vào từ điển và không bao giờ đọc từ nó một lần nữa, sau đó nó phục vụ không có mục đích và bạn có thể loại bỏ nó hoàn toàn. – Timwi

1

Như Rob chỉ ra nó không được khuyến khích bạn có quyền truy cập vào các lĩnh vực tư nhân, nhưng nếu bạn desperatly phải và không thể thực sự kiểm tra giá trị được asigned đến lĩnh vực mà bạn có thể làm theo cách này:

 Type sampleType = sampleInstance.GetType(); 
     FieldInfo fieldInfo = sampleType.GetField("_values", BindingFlags.Instance, BindingFlags.NonPublic); 
     Dictionary<string, string> info = fieldInfo.GetValue(sampleType); 
Các vấn đề liên quan