2010-09-29 20 views
5

Giả sử tôi có một thói quen tư nhân thực hiện một số tính toán:Làm thế nào để kiểm tra đơn vị mã riêng mà không cần tái cấu trúc để phân lớp?

private function TCar.Speed: float 
{ 
    Result = m_furlogs * 23; 
} 

Nhưng bây giờ tôi muốn bắt đầu thử nghiệm tính toán này triệt để hơn, vì vậy tôi refactor nó ra một chức năng riêng biệt:

public function TCar.Speed: float 
{ 
    Result = CalculateSpeed(m_furlogs); 
} 

private function TCar.CalculateSpeed(single furlogs): float 
{ 
    Result = furlogs * 23; 
} 

Bây giờ tôi có thể thực hiện tất cả các loại thử nghiệm trên CalculateSpeed:

Check(CalculateSpeed(0) = 0); 
Check(CalculateSpeed(1) = 23); 
Check(CalculateSpeed(2) = 46); 
Check(CalculateSpeed(88) = -1); 

Ngoại trừ việc tôi không thể thực hiện các thử nghiệm này, vì CalculateSpeed là riêng tư để TCar. Một tennant trừu tượng của kiểm thử đơn vị là bạn không bao giờ thử nghiệm mã riêng - chỉ các giao diện công khai. Là một vấn đề thực tế, * x * Đơn vị thường không được cấu trúc để có thể truy cập các phương thức riêng của lớp riêng biệt đang được thử nghiệm.

Vấn đề là không có phần còn lại của lớp được thiết lập để xử lý các bài kiểm tra đơn vị. Đây là thói quen đầu tiên sẽ có thử nghiệm dưới bất kỳ hình thức nào. Và rất khó để cấu hình lớp máy chủ một tập hợp các điều kiện ban đầu sẽ cho phép tôi kiểm tra việc gọi số CalculateSpeed với mọi bộ đầu vào mà tôi muốn.

Lựa chọn duy nhất tôi có thể nhìn thấy, đang chuyển động tính tin này ra vào nó riêng của TCarCalculateSpeed lớp:

public class TCarCalculateSpeed 
{ 
    public function CalculateSpeed(float furlogs) 
    { 
     Result = furlogs * 23; 
    } 
} 

Cả lớp, dành riêng cho phơi bày một phương pháp, đó là nghĩa vụ phải được tư nhân, chỉ vì vậy tôi có thể kiểm tra nó?

Nổ lớp.

Plus là riêng tư. Nếu tôi muốn nó được công khai, tôi muốn quảng cáo nó đến công khai khả năng hiển thị - ít nhất theo cách đó tôi lưu một lớp riêng biệt được tạo ra.

Tôi muốn thêm một số thử nghiệm đơn vị; nhưng nó chỉ có thể được thực hiện thành từng mảnh nhỏ, khi thay đổi mã. tôi không thể thiết kế lại hoàn toàn chức năng phần mềm 12 tuổi, có thể phá vỡ tất cả mọi thứ, bởi vì tôi muốn thử nghiệm một tính toán nội bộ.

hiện nay, tốt nhất, suy nghĩ của tôi là để thêm một phương pháp Test đến lớp Car của tôi, và chỉ cần gọi rằng:

TCar Car = new TCar(); 
Car.RunTests; 

public procedure TCar.RunTests 
{ 
    Check(CalculateSpeed(0) = 0); 
    Check(CalculateSpeed(1) = 23); 
    Check(CalculateSpeed(2) = 46); 
    Check(CalculateSpeed(88) = -1); 
} 

Nhưng bây giờ tôi phải tìm ra cách để có TCar.RunTests được trigged bởi bên ngoài TestRunner , chỉ được thiết kế để sử dụng các lớp học TestCase.

Lưu ý: Tôi đã cố gắng hết sức để kết hợp cú pháp từ nhiều ngôn ngữ. Nói cách khác: ngôn ngữ bất khả tri.

+0

Tôi không biết cách làm theo cách bất khả tri về ngôn ngữ, nhưng trong VS/.NET, nó sẽ tạo ra một lớp Accessor, lớp bóng của bạn và làm mọi thứ công khai để bạn có thể kiểm tra nó. – CaffGeek

+0

Đó có thể là câu trả lời có sẵn cho tôi. tôi phải tạo phương thức 'protected', thay vì' private', nhưng sau đó tôi có thể truy cập các thành viên được bảo vệ từ tệp mã kiểm thử đơn vị của tôi. –

Trả lời

3

Điều này có thể không thực sự khá bất khả tri về ngôn ngữ, vì cơ chế bảo vệ và chiến thuật vượt qua chúng thay đổi khá rộng rãi với ngôn ngữ.

Nhưng hầu hết các ngôn ngữ đều cung cấp bỏ qua ở một dạng nào đó và như những người khác đã lưu ý, đôi khi có sự bảo vệ giữa đường riêng và công khai giúp việc kiểm tra dễ dàng hơn.

Trong Java, ví dụ, phản chiếu có thể được sử dụng cho nội dung riêng tư nếu bạn thực sự cần, và mọi thứ có thể được bảo vệ hoặc gói riêng tư để bạn không cần phản ánh.

Nói chung, nếu có điều gì đó phức tạp, đủ để yêu cầu kiểm tra, nó không nên được chôn cất như một phương pháp hoặc lớp học riêng tư. Nó đang làm một cái gì đó bảo đảm lớp riêng của nó.

Thay vì lo lắng về số lượng lớp học, hãy lo lắng về kích thước và mức độ phức tạp của chúng. Nhiều lớp học nhỏ tôn trọng các Single Responsibility Principle là tốt hơn so với một số ít các lớp học làm những điều phức tạp trong nội bộ.

+0

Hầu hết mọi người đều ủng hộ một số loại mẹo ngôn ngữ để bỏ qua các biện pháp bảo vệ khả năng truy cập trên phương pháp này. Điều này có lẽ là những gì tôi muốn kết thúc bằng cách sử dụng trong ngôn ngữ mà tôi đang sử dụng. tôi đã chọn để đưa ra câu trả lời cho donroby, mặc dù hầu hết các bạn đều có cùng một ý tưởng. –

+1

@Ian - Cảm ơn. Nhưng hãy nhớ lời khuyên chính của tôi, và của một số người khác, đó là việc bạn thực sự lôi nó ra một lớp khác và kiểm tra nó bằng nhiều cách bình thường hơn. Thật tuyệt khi biết cách vượt qua sự bảo vệ, nhưng thường không phải là một ý tưởng hay. –

1

Bạn có thể tạo nhiều phiên bản của lớp TCar với các giá trị ban đầu khác nhau của m_furlog không? Bạn có một getter trên tốc độ bất cứ nơi nào? Bạn có thể xác nhận điều đó nếu có.

Nếu nó chỉ được sử dụng nội bộ, và bạn thực sự muốn kiểm tra nó, bạn có thể tạo một lớp tiện ích giữ logic cho các phép tính đơn giản. Tôi biết đó là tái cấu trúc, nhưng nó không phải là vụ nổ lớp mà bạn có thể đang hình dung.

+0

+1 cho đoạn thứ 2.Tách nó ra là một sự cân bằng mà tôi cho rằng yêu cầu suy nghĩ cẩn thận trong từng trường hợp. Sự đồng thuận chính là sử dụng các thủ thuật của ngôn ngữ để vượt qua sự bảo vệ đối tượng và kiểm tra nó tại chỗ. May mắn là ngôn ngữ của tôi có những hacks như vậy - vì vậy tôi sẽ làm điều đó. –

3

Nếu một phương pháp phức tạp (và nguy hiểm) đủ để tự kiểm tra, nó đáng để tạo một lớp cho nó hoặc biến nó thành thành viên công khai của lớp hiện tại - tùy theo điều kiện nào phù hợp hơn .

1

Có thể bạn có thể tạo một lớp kiểm tra xuất phát từ lớp học của bạn đang được kiểm tra?

Dưới đây là một ví dụ từ một SO question

+0

Khuôn khổ tôi muốn sử dụng không thể làm điều đó, nhưng nó là một ý tưởng hợp lệ. +1 –

1

Trong một số ngôn ngữ, có căn cứ trung gian giữa tư nhân và công cộng. Bạn có thể phơi bày một phương pháp riêng tư hợp lý để kiểm tra đơn vị mà không để lộ nó với thế giới.

Trong tài liệu phương pháp, bạn có thể ghi lại rằng phương pháp này là dành riêng, nhưng có thể truy cập cho mục đích thử nghiệm đơn vị.

Trong Java, ví dụ, bạn có thể thực hiện phương thức riêng package protected và đặt kiểm tra đơn vị trong cùng một gói. Trong C#, nếu tôi nhớ lại chính xác, bạn có thể làm cho nó nội bộ. Trong C++, bài kiểm tra đơn vị có thể là một người bạn.

1

Nếu ngôn ngữ của bạn hỗ trợ trình biên dịch xác định, bạn có thể sử dụng chúng cho lợi thế của bạn.

(Ví dụ mã trong Delphi)

Trong dự án đơn vị thử nghiệm của bạn, thiết lập một trình biên dịch có điều kiện xác định, hoặc sử dụng các tùy chọn dự án hoặc trong một tập tin bao gồm rằng bạn bao gồm trong mỗi đơn vị trong dự án đó.

{$DEFINE UNIT_TESTS} 

Trong mã lớp học của bạn, kiểm tra các điều kiện xác định và chuyển đổi giữa công cộng hoặc protected and private phù hợp:

{$IFDEF UNIT_TESTS} 
    public // or protected 
{$ELSE} 
    private 
{$ENDIF} 
    function CalculateSpeed: float; 

Điều này có nghĩa kiểm tra đơn vị của bạn sẽ có quyền truy cập mà họ cần để phương pháp của bạn, trong khi ở mã sản xuất nó vẫn sẽ là riêng tư.

+0

Đó là một lưu ý tốt. –

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