Làm thế nào để bạn kiểm tra các phương pháp riêng tư với NUnit?


104

Tôi đang tự hỏi làm thế nào để sử dụng NUnit một cách chính xác. Đầu tiên, tôi đã tạo một dự án thử nghiệm riêng biệt sử dụng dự án chính của tôi làm tài liệu tham khảo. Nhưng trong trường hợp đó, tôi không thể thử nghiệm các phương pháp riêng tư. Tôi đoán là tôi cần đưa mã thử nghiệm vào mã chính của mình ?! - Đó dường như không phải là cách chính xác để làm điều đó. (Tôi không thích ý tưởng về mã vận chuyển với các bài kiểm tra trong đó.)

Làm thế nào để bạn kiểm tra các phương pháp riêng tư với NUnit?

Câu trả lời:


74

Nói chung, kiểm thử đơn vị giải quyết giao diện công khai của một lớp, trên lý thuyết rằng việc triển khai là phi quan trọng, miễn là kết quả đúng theo quan điểm của khách hàng.

Vì vậy, NUnit không cung cấp bất kỳ cơ chế nào để kiểm tra các thành viên không công khai.


1
+1 Tôi vừa đưa ra ý kiến ​​chống lại vấn đề này và trong trường hợp của tôi, có một thuật toán "ánh xạ" xảy ra giữa ý nghĩa riêng tư và công khai nếu tôi tham gia Unit Test công khai, nó thực sự sẽ là một bài kiểm tra tích hợp. Trong trường hợp này, tôi nghĩ rằng nó đang cố gắng viết các điểm kiểm tra cho một vấn đề thiết kế trong mã. trong trường hợp đó, tôi có thể nên tạo một lớp khác thực hiện phương thức "riêng tư" đó.
andy

140
Tôi hoàn toàn không đồng ý với lập luận này. Kiểm thử đơn vị không phải về lớp, mà là về . Nếu tôi có một lớp với một phương thức công khai và mười phương thức riêng được sử dụng để tạo kết quả của phương thức công khai, tôi không có cách nào đảm bảo mỗi phương thức riêng hoạt động theo cách đã định. Tôi có thể cố gắng tạo các trường hợp thử nghiệm trên phương thức công khai đánh đúng phương pháp riêng tư theo đúng cách. Nhưng sau đó tôi không biết liệu phương thức private có thực sự được gọi hay không, trừ khi tôi tin tưởng phương thức public sẽ không bao giờ thay đổi. Các phương pháp riêng tư nhằm mục đích riêng tư cho người dùng sản xuất mã, không phải tác giả.
Quango 17/01/13

3
@Quango, trong thiết lập thử nghiệm tiêu chuẩn, "tác giả" người dùng sản xuất mã. Tuy nhiên, nếu bạn không ngửi thấy vấn đề thiết kế, bạn có các tùy chọn để thử nghiệm các phương pháp không công khai mà không làm thay đổi lớp. System.Reflectioncho phép bạn truy cập và gọi các phương thức không công khai bằng cách sử dụng cờ ràng buộc, vì vậy bạn có thể hack NUnit hoặc thiết lập khuôn khổ của riêng mình. Hoặc (tôi nghĩ dễ dàng hơn), bạn có thể thiết lập cờ thời gian biên dịch (#if TESTING) để thay đổi các công cụ sửa đổi quyền truy cập, cho phép bạn sử dụng các khuôn khổ hiện có.
harpo

23
Một phương pháp riêng là một chi tiết triển khai. Điểm mấu chốt của việc kiểm tra đơn vị là cho phép cấu trúc lại việc thực hiện mà không thay đổi hành vi . Nếu các phương thức private trở nên phức tạp đến mức người ta muốn bao phủ chúng bằng các phép thử riêng lẻ, thì bổ đề này có thể được sử dụng: "Một phương thức private luôn có thể là một phương thức public (hoặc nội bộ) của một lớp riêng biệt". Có nghĩa là, nếu một phần logic đủ nâng cao để có thể được kiểm tra, nó có thể là ứng cử viên để trở thành lớp của chính nó, với các bài kiểm tra của riêng nó.
Anders Forsgren

6
@AndersForsgren Nhưng quan điểm của kiểm thử đơn vị , trái ngược với kiểm tra tích hợp hoặc kiểm tra chức năng , chính xác là để kiểm tra các chi tiết như vậy. Và mức độ phủ mã được coi là một số liệu kiểm tra đơn vị quan trọng, vì vậy về lý thuyết, mọi phần logic đều "đủ nâng cao để có thể kiểm tra".
Kyle Strand,

57

Mặc dù tôi đồng ý rằng trọng tâm của thử nghiệm đơn vị phải là giao diện công khai, nhưng bạn sẽ có ấn tượng chi tiết hơn về mã của mình nếu bạn cũng thử nghiệm các phương pháp riêng tư. Khung thử nghiệm MS cho phép điều này thông qua việc sử dụng PrivateObject và PrivateType, NUnit thì không. Những gì tôi làm thay vào đó là:

private MethodInfo GetMethod(string methodName)
{
    if (string.IsNullOrWhiteSpace(methodName))
        Assert.Fail("methodName cannot be null or whitespace");

    var method = this.objectUnderTest.GetType()
        .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

    if (method == null)
        Assert.Fail(string.Format("{0} method not found", methodName));

    return method;
}

Bằng cách này có nghĩa là bạn không phải thỏa hiệp với việc đóng gói để có lợi cho khả năng kiểm tra. Hãy nhớ rằng bạn sẽ cần phải sửa đổi BindingFlags của mình nếu bạn muốn thử nghiệm các phương thức tĩnh riêng tư. Ví dụ trên chỉ là các phương thức ví dụ.


7
Thử nghiệm các phương pháp trợ giúp nhỏ đó nắm bắt phần đơn vị trong thử nghiệm đơn vị. Không phải tất cả đều phù hợp với các lớp tiện ích.
Johan Larsson

12
Đây chính xác là những gì tôi cần. Cảm ơn! Tất cả những gì tôi cần là kiểm tra xem trường riêng tư có được đặt đúng cách hay không và tôi KHÔNG cần dành 3 giờ để tìm cách xác định điều đó thông qua giao diện công khai. Đây là mã hiện có không thể được cấu trúc lại theo ý thích. Thật buồn cười như thế nào là một câu hỏi đơn giản có thể được giải đáp với giáo điều lý tưởng ...
Droj

5
Đây phải là câu trả lời được chọn, vì nó là câu trả lời duy nhất thực sự trả lời câu hỏi.
bavaza

6
Đã đồng ý. Câu trả lời được chọn có giá trị của nó, nhưng là câu trả lời cho "tôi có nên thử nghiệm các phương pháp riêng tư", không phải câu hỏi của OP.
chesterbr

2
nó hoạt động. Cảm ơn! Đây là những gì nhiều người đang tìm kiếm for.This phải là câu trả lời được lựa chọn,
Có khả năng Johnson

47

Một khuôn mẫu phổ biến để viết các bài kiểm tra đơn vị là chỉ kiểm tra các phương pháp công khai.

Nếu bạn nhận thấy rằng bạn có nhiều phương thức riêng tư muốn kiểm tra, thì thông thường đây là dấu hiệu cho thấy bạn nên cấu trúc lại mã của mình.

Sẽ là sai nếu công khai các phương thức này trên lớp mà chúng hiện đang sống. Điều đó sẽ phá vỡ hợp đồng mà bạn muốn lớp đó có.

Có thể đúng nếu chuyển chúng sang lớp trợ giúp và công khai chúng ở đó. Lớp này có thể không được hiển thị bởi API của bạn.

Bằng cách này, mã kiểm tra không bao giờ bị trộn lẫn với mã công khai của bạn.

Một vấn đề tương tự là thử nghiệm các lớp riêng tức là. các lớp bạn không xuất ra khỏi assembly của bạn. Trong trường hợp này, bạn có thể đặt cụm mã thử nghiệm của mình một cách rõ ràng là bạn của cụm mã sản xuất bằng cách sử dụng thuộc tính InternalsVibleTo.


1
+ 1 vâng! Tôi vừa đi đến kết luận đó trong khi viết các bài kiểm tra của mình, lời khuyên tốt!
andy

1
Di chuyển các phương thức riêng tư mà bạn muốn kiểm tra nhưng không hiển thị cho người dùng API sang một lớp khác không được hiển thị và đặt chúng ở chế độ công khai ở đó chính xác là những gì tôi đang tìm kiếm.
Thomas N

cảm ơn @morechilli. Chưa bao giờ nhìn thấy InternalsVibleTo trước đây. Giúp kiểm tra dễ dàng hơn nhiều.
Andrew MacNaughton

Chào. Gần đây đã nhận được một số phiếu bầu không có ý kiến. Vui lòng cung cấp một số phản hồi để giải thích suy nghĩ hoặc mối quan tâm của bạn.
morechilli

6
Vì vậy, nếu bạn có một phương thức riêng tư được gọi ở nhiều nơi trong một lớp để thực hiện một điều gì đó rất cụ thể chỉ được lớp đó cần và nó không được tiết lộ như một phần của API công khai ... bạn đang nói rằng hãy đặt nó vào một trình trợ giúp lớp chỉ để kiểm tra? Bạn cũng có thể công khai nó cho cả lớp.
Daniel Macias

21

Có thể kiểm tra các phương pháp riêng bằng cách khai báo hội thử nghiệm của bạn là một tổ hợp bạn bè của tổ hợp mục tiêu mà bạn đang thử nghiệm. Xem liên kết bên dưới để biết chi tiết:

http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

Điều này có thể hữu ích vì nó chủ yếu tách mã thử nghiệm của bạn khỏi mã sản xuất của bạn. Bản thân tôi chưa bao giờ sử dụng phương pháp này vì tôi chưa bao giờ thấy cần nó. Tôi cho rằng bạn có thể sử dụng nó để thử và kiểm tra các trường hợp thử nghiệm cực đoan mà bạn chỉ đơn giản là không thể sao chép trong môi trường thử nghiệm của mình để xem cách mã của bạn xử lý nó.

Như đã nói, bạn thực sự không cần phải thử nghiệm các phương pháp riêng tư. Bạn không chỉ likley muốn cấu trúc lại mã của mình thành các khối xây dựng nhỏ hơn. Một mẹo có thể giúp ích cho bạn khi bạn đến với refactor là hãy thử và suy nghĩ về miền mà hệ thống của bạn có liên quan và nghĩ về các đối tượng 'thực' sống trong miền này. Các đối tượng / lớp trong hệ thống của bạn phải liên quan trực tiếp đến một đối tượng thực, điều này sẽ cho phép bạn tách biệt hành vi chính xác mà đối tượng đó phải chứa và cũng giới hạn trách nhiệm của đối tượng. Điều này có nghĩa là bạn đang cấu trúc lại một cách hợp lý thay vì chỉ để làm cho nó có thể thử nghiệm một phương pháp cụ thể; bạn sẽ có thể kiểm tra hành vi của các đối tượng.

Nếu bạn vẫn cảm thấy cần phải kiểm tra nội bộ thì bạn cũng có thể muốn xem xét việc chế nhạo trong thử nghiệm của mình vì bạn đang muốn tập trung vào một đoạn mã. Chế nhạo là nơi bạn đưa một đối tượng phụ thuộc vào nó nhưng các đối tượng được đưa vào không phải là đối tượng 'thực' hoặc đối tượng sản xuất. Chúng là các đối tượng giả có hành vi được mã hóa cứng để giúp dễ dàng hơn trong việc phân lập các lỗi hành vi. Rhino.Mocks là một khuôn khổ mô phỏng miễn phí phổ biến về cơ bản sẽ viết các đối tượng cho bạn. TypeMock.NET (một sản phẩm thương mại có sẵn phiên bản cộng đồng) là một khuôn khổ mạnh mẽ hơn có thể giả các đối tượng CLR. Rất hữu ích để chế nhạo các lớp SqlConnection / SqlCommand và Datatable chẳng hạn khi thử nghiệm một ứng dụng cơ sở dữ liệu.

Hy vọng rằng câu trả lời này sẽ cung cấp cho bạn thêm một chút thông tin để cung cấp cho bạn về Unit Testing nói chung và giúp bạn có được kết quả tốt hơn từ Unit Testing.


12
Có thể kiểm tra các phương pháp nội bộ , không riêng tư (với NUnit).
TrueWill

6

Tôi ủng hộ khả năng kiểm tra các phương pháp riêng tư. Khi xUnit khởi động, nó được dùng để kiểm tra chức năng sau khi mã được viết. Kiểm tra giao diện là đủ cho mục đích này.

Kiểm thử đơn vị đã phát triển thành phát triển theo hướng kiểm tra. Có khả năng kiểm tra tất cả các phương pháp hữu ích cho ứng dụng đó.


5

Câu hỏi này đã có trong những năm cao cấp, nhưng tôi nghĩ tôi sẽ chia sẻ cách làm của mình.

Về cơ bản, tôi có tất cả các lớp thử nghiệm đơn vị của mình trong hợp ngữ mà chúng đang thử nghiệm trong không gian tên 'UnitTest' bên dưới 'mặc định' cho hợp ngữ đó - mỗi tệp thử nghiệm được bao bọc trong một:

#if DEBUG

...test code...

#endif

và tất cả điều đó có nghĩa là a) nó không được phân phối trong một bản phát hành và b) Tôi có thể sử dụng internal/Friend khai báo cấp mà không cần nhảy vòng.

Điều khác mà điều này cung cấp, phù hợp hơn với câu hỏi này, là việc sử dụng các partiallớp, có thể được sử dụng để tạo proxy để kiểm tra các phương thức riêng tư, vì vậy, ví dụ để kiểm tra một cái gì đó như phương thức riêng trả về một giá trị nguyên:

public partial class TheClassBeingTested
{
    private int TheMethodToBeTested() { return -1; }
}

trong các lớp chính của assembly và lớp thử nghiệm:

#if DEBUG

using NUnit.Framework;

public partial class TheClassBeingTested
{
    internal int NUnit_TheMethodToBeTested()
    {
        return TheMethodToBeTested();
    }
}

[TestFixture]
public class ClassTests
{
    [Test]
    public void TestMethod()
    {
        var tc = new TheClassBeingTested();
        Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
    }
}

#endif

Rõ ràng, bạn cần đảm bảo rằng bạn không sử dụng phương pháp này trong khi phát triển, mặc dù bản dựng Bản phát hành sẽ sớm chỉ ra một lệnh gọi vô tình đến nó nếu bạn làm vậy.


4

Mục tiêu chính của kiểm thử đơn vị là kiểm tra các phương thức công khai của một lớp. Những phương thức công khai sẽ sử dụng những phương thức riêng tư đó. Kiểm thử đơn vị sẽ kiểm tra hành vi của những gì được cung cấp công khai.


3

Xin lỗi nếu điều này không trả lời được câu hỏi nhưng các giải pháp như sử dụng phản chiếu, câu lệnh #if #endif hoặc hiển thị các phương thức riêng tư không giải quyết được sự cố. Có thể có một số lý do cho việc không hiển thị các phương pháp riêng tư ... điều gì sẽ xảy ra nếu đó là mã sản xuất và nhóm đang viết lại các bài kiểm tra đơn vị chẳng hạn.

Đối với dự án mà tôi đang làm việc chỉ MSTest (đáng buồn là) dường như có một cách, sử dụng trình truy cập, để kiểm tra đơn vị các phương pháp riêng tư.


2

Bạn không kiểm tra các chức năng riêng tư. Có nhiều cách để sử dụng sự phản chiếu để truy cập vào các phương thức và thuộc tính private. Nhưng điều đó không thực sự dễ dàng và tôi thực sự không khuyến khích cách làm này.

Đơn giản là bạn không nên thử nghiệm bất cứ thứ gì không công khai.

Nếu bạn có một số phương pháp và thuộc tính nội bộ, bạn nên cân nhắc thay đổi điều đó thành công khai hoặc gửi các thử nghiệm của bạn với ứng dụng (điều mà tôi thực sự không thấy là vấn đề).

Nếu khách hàng của bạn có thể chạy Test-Suite và thấy rằng mã bạn phân phối đang thực sự "hoạt động", thì tôi không thấy đây là vấn đề (miễn là bạn không cung cấp IP của mình thông qua việc này). Những thứ tôi đưa vào mỗi bản phát hành là báo cáo thử nghiệm và báo cáo về mã.


Một số khách hàng cố gắng giữ ngân sách nhỏ và bắt đầu thảo luận về phạm vi thử nghiệm. Thật khó để giải thích những người này rằng bài kiểm tra viết không phải vì bạn là một lập trình viên tồi và không tin tưởng vào kỹ năng của bản thân.
MrFox 30/10/08

1

Về lý thuyết của Unit Testing chỉ nên thử nghiệm hợp đồng. tức là chỉ các thành viên công khai của lớp. Nhưng trong thực tế, nhà phát triển thường muốn kiểm tra các thành viên nội bộ. - và nó không tệ. Đúng, nó đi ngược lại với lý thuyết, nhưng trong thực tế, đôi khi nó có thể hữu ích.

Vì vậy, nếu bạn thực sự muốn kiểm tra các thành viên nội bộ, bạn có thể sử dụng một trong các phương pháp sau:

  1. Đặt thành viên của bạn ở chế độ công khai. Trong nhiều cuốn sách, các tác giả đề xuất cách tiếp cận này đơn giản
  2. Bạn có thể đặt bạn làm thành viên nội bộ và thêm InternalVibleTo để đảm bảo
  3. Bạn có thể làm cho các thành viên trong lớp được bảo vệ và kế thừa lớp thử nghiệm của bạn từ lớp đang thử nghiệm của bạn.

Ví dụ về mã (mã giả):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}

Có vẻ như con gián đang ẩn bên trong mã ví dụ của bạn;) Phương thức bên trong vật cố định của NUnit phải được công khai, nếu không bạn sẽ nhận được Message: Method is not public.
Gucu112

@ Gucu112 Cảm ơn. Tôi sửa nó rồi. Nói chung, nó không quan trọng vì mục tiêu là hiển thị aproach từ pov thiết kế.
burzhuy

1

Bạn có thể đặt các phương thức của mình được bảo vệ bên trong và sau đó sử dụng assembly: InternalsVisibleTo("NAMESPACE") không gian tên thử nghiệm của mình.

Do đó, KHÔNG! Bạn không thể truy cập các phương thức riêng tư, nhưng đây là một giải pháp khắc phục.


0

Tôi sẽ hiển thị gói phương thức riêng tư. Bằng cách đó, bạn giữ nó ở chế độ riêng tư hợp lý trong khi vẫn có thể kiểm tra các phương pháp đó. Tôi không đồng ý với việc mọi người nói rằng các giao diện công cộng là những giao diện duy nhất nên được thử nghiệm. Thường có mã thực sự quan trọng trong các phương thức riêng tư không thể được kiểm tra chính xác bằng cách chỉ đi qua các giao diện bên ngoài.

Vì vậy, nó thực sự sôi nổi nếu bạn quan tâm nhiều hơn đến mã chính xác hoặc ẩn thông tin. Tôi muốn nói rằng khả năng hiển thị của gói là một sự thỏa hiệp tốt vì để truy cập vào phương thức đó, ai đó sẽ phải đặt lớp của họ trong gói của bạn. Điều đó thực sự sẽ khiến họ phải suy nghĩ lại xem đó có phải là điều thực sự thông minh để làm hay không.

Tôi là một chàng trai Java btw, vì vậy gói visiblilty có thể được gọi là một cái gì đó hoàn toàn khác trong C #. Đủ để nói rằng đó là khi hai lớp phải ở trong cùng một không gian tên để truy cập các phương thức đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.