2008-08-10 18 views
8

Gần đây tôi đã phải thay đổi một số mã trên các hệ thống cũ hơn, nơi không phải tất cả các mã đều có kiểm tra đơn vị.
Trước khi thực hiện các thay đổi tôi muốn viết các bài kiểm tra, nhưng mỗi lớp đã tạo ra rất nhiều phụ thuộc và các mẫu chống khác làm cho thử nghiệm khá khó.
Rõ ràng, tôi muốn cấu trúc lại mã để dễ kiểm tra, viết các bài kiểm tra và sau đó thay đổi nó.
Đây có phải là cách bạn muốn làm không? Hoặc bạn sẽ dành rất nhiều thời gian viết các bài kiểm tra khó viết mà hầu như sẽ bị xóa sau khi việc tái cấu trúc sẽ được hoàn thành?Làm cách nào để bạn kiểm tra/thay đổi mã chưa được kiểm tra và không thể kiểm tra?

Trả lời

5

Trước hết, here's a great article with tips on unit testing. Thứ hai, tôi tìm thấy một cách tuyệt vời để tránh thực hiện tấn thay đổi trong mã cũ là chỉ refactor nó một chút cho đến khi bạn có thể kiểm tra nó. Một cách dễ dàng để làm điều này là làm cho các thành viên riêng được bảo vệ, và sau đó ghi đè lên trường được bảo vệ.

Ví dụ: giả sử bạn có một lớp tải một số nội dung từ cơ sở dữ liệu trong quá trình khởi tạo. Trong trường hợp này, bạn không thể chỉ ghi đè lên một phương thức được bảo vệ, nhưng bạn có thể trích xuất logic DB thành một trường được bảo vệ và sau đó ghi đè lên nó trong thử nghiệm.

public class MyClass { 
    public MyClass() { 
     // undesirable DB logic 
    } 
} 

trở thành

public class MyClass { 
    public MyClass() { 
     loadFromDB(); 
    } 

    protected void loadFromDB() { 
     // undesirable DB logic 
    } 
} 

và sau đó thử nghiệm của bạn trông giống như sau:

public class MyClassTest { 
    public void testSomething() { 
     MyClass myClass = new MyClassWrapper(); 
     // test it 
    } 

    private static class MyClassWrapper extends MyClass { 
     @Override 
     protected void loadFromDB() { 
      // some mock logic 
     } 
    } 
} 

Đây là phần nào của một tấm gương xấu, bởi vì bạn có thể sử dụng DBUnit trong trường hợp này, nhưng tôi thực sự đã làm điều này trong một trường hợp tương tự gần đây vì tôi muốn kiểm tra một số chức năng hoàn toàn không liên quan đến dữ liệu đang được tải, vì vậy nó rất hiệu quả. Tôi cũng tìm thấy việc phơi bày các thành viên như vậy có ích trong các trường hợp tương tự khác mà tôi cần phải loại bỏ một số phụ thuộc đã ở trong một lớp học trong một thời gian dài.

Tôi khuyên bạn nên chống lại giải pháp này nếu bạn đang viết một khuôn khổ mặc dù, trừ khi bạn thực sự không nhớ để lộ các thành viên cho người dùng khung của bạn.

Đó là một chút hack, nhưng tôi thấy nó khá hữu ích.

0

Tôi không chắc chắn lý do tại sao bạn sẽ nói rằng các bài kiểm tra đơn vị sẽ bị xóa sau khi quá trình tái cấu trúc hoàn tất. Trên thực tế, bộ thử nghiệm đơn vị của bạn nên chạy sau khi xây dựng chính (bạn có thể tạo một bản thử nghiệm "riêng biệt", chỉ chạy thử nghiệm đơn vị sau khi sản phẩm chính được tạo). Sau đó, bạn sẽ ngay lập tức thấy nếu thay đổi trong một mảnh phá vỡ các bài kiểm tra trong hệ thống phụ khác. Lưu ý rằng có một chút khác biệt so với chạy thử nghiệm trong khi xây dựng (như một số có thể biện hộ) - một số thử nghiệm giới hạn hữu ích trong quá trình xây dựng, nhưng thường là không hiệu quả để "hỏng" quá trình xây dựng chỉ vì một số kiểm tra đơn vị xảy ra không thành công.

Nếu bạn đang viết Java (rất có thể), hãy kiểm tra http://www.easymock.org/ - có thể hữu ích để giảm khớp nối cho mục đích thử nghiệm.

3

@valters

Tôi không đồng ý với tuyên bố của mình rằng các xét nghiệm không nên phá vỡ xây dựng. Các bài kiểm tra nên là một dấu hiệu cho thấy ứng dụng không có lỗi mới được giới thiệu cho chức năng được kiểm tra (và một lỗi tìm thấy là một dấu hiệu của một bài kiểm tra còn thiếu).

Nếu kiểm tra không phá vỡ bản dựng, thì bạn có thể dễ dàng gặp phải tình huống mã mới phá vỡ bản dựng và nó không được biết trong một thời gian, mặc dù thử nghiệm đã được kiểm tra. Một thử nghiệm không thành công nên là một lá cờ đỏ hoặc là thử nghiệm hoặc mã phải được sửa.

Hơn nữa, cho phép các phép thử không phá vỡ bản xây dựng sẽ làm cho tốc độ thất bại tăng chậm, đến mức bạn không còn có bộ kiểm tra hồi quy đáng tin cậy nữa.

Nếu có vấn đề với kiểm tra phá vỡ quá thường xuyên, có thể là một dấu hiệu cho thấy các bài kiểm tra được viết theo cách quá mong manh (phụ thuộc vào tài nguyên có thể thay đổi, chẳng hạn như cơ sở dữ liệu mà không sử dụng DB Unit đúng cách, hoặc một dịch vụ web bên ngoài nên được chế nhạo), hoặc nó có thể là một dấu hiệu cho thấy có các nhà phát triển trong nhóm không cung cấp cho các bài kiểm tra sự chú ý thích hợp.

Tôi tin chắc rằng thử nghiệm không thành công nên được khắc phục càng sớm càng tốt, giống như bạn sửa mã không thể biên dịch ASAP.

0

Tôi đã đọc Làm việc hiệu quả với Mã kế thừa và tôi đồng ý rằng nó rất hữu ích để xử lý mã "không thể kiểm chứng".

Một số kỹ thuật chỉ áp dụng cho các ngôn ngữ được biên dịch (Tôi đang làm việc trên các ứng dụng PHP "cũ"), nhưng tôi cho rằng hầu hết sách đều có thể áp dụng cho bất kỳ ngôn ngữ nào.

Sách tái cấu trúc đôi khi giả sử mã ở trạng thái nửa lý tưởng hoặc "bảo trì" trước khi cấu trúc lại, nhưng hệ thống tôi hoạt động ít hơn lý tưởng và được phát triển dưới dạng ứng dụng "tìm hiểu khi bạn đi" hoặc ứng dụng đầu tiên đối với một số công nghệ được sử dụng (và tôi không đổ lỗi cho các nhà phát triển ban đầu cho điều đó, vì tôi là một trong số họ), vì vậy không có thử nghiệm nào cả, và mã đôi khi lộn xộn. Cuốn sách này giải quyết loại tình huống này, trong khi các sách tái cấu trúc khác thường không (tốt, không đến mức này).

Tôi nên đề cập đến việc tôi chưa nhận được tiền từ biên tập viên cũng như tác giả của cuốn sách này), nhưng tôi thấy nó rất thú vị, vì tài nguyên thiếu trong lĩnh vực mã kế thừa (và đặc biệt là ngôn ngữ của tôi, Tiếng Pháp, nhưng đó là một câu chuyện khác).