Lập trình dựa trên hợp đồng và kiểm tra đơn vị


13

Tôi là một lập trình viên phòng thủ và là một fan hâm mộ lớn của Hợp đồng Mã microsofts.

Bây giờ tôi không thể luôn sử dụng C # và trong hầu hết các ngôn ngữ, công cụ duy nhất tôi có là các xác nhận. Vì vậy, tôi thường kết thúc với mã như thế này:

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

Tuy nhiên, mô hình này (hoặc bất cứ điều gì bạn sẽ gọi nó) dẫn đến rất nhiều mã lộn xộn.

Tôi đã bắt đầu tự hỏi nếu nó thực sự đáng nỗ lực và liệu thử nghiệm đơn vị thích hợp sẽ bao gồm điều này?


6
Mặc dù các thử nghiệm đơn vị cho phép di chuyển các xác nhận ra khỏi mã ứng dụng (và do đó tránh lộn xộn), hãy xem xét rằng chúng không thể kiểm tra mọi thứ có thể xảy ra trong hệ thống sản xuất thực. Vì vậy, hợp đồng mã IMO có một số lợi thế, đặc biệt đối với mã quan trọng trong đó tính chính xác là đặc biệt quan trọng.
Giorgio

Vì vậy, về cơ bản thời gian phát triển, khả năng bảo trì, khả năng đọc và độ bao phủ mã tốt hơn?
ronag

1
Tôi chủ yếu sử dụng xác nhận trong mã để kiểm tra tính chính xác của thông số (ví dụ về null) và trong kiểm tra đơn vị cũng kiểm tra thêm các xác nhận đó.
artjom

Câu trả lời:


14

Tôi không nghĩ bạn nên nghĩ nó là "vs".
Như đã đề cập trong các nhận xét của @Giorgio, các hợp đồng mã là để kiểm tra các bất biến (trong môi trường sản xuất) và kiểm tra đơn vị là để đảm bảo mã của bạn hoạt động như mong đợi khi các điều kiện đó được đáp ứng.


2
Tôi nghĩ điều quan trọng là phải kiểm tra xem mã có hoạt động hay không (ví dụ: nó ném ngoại lệ) khi các điều kiện không được đáp ứng.
Svick

6

Hợp đồng giúp bạn có ít nhất một điều mà bài kiểm tra đơn vị không làm được. Khi bạn đang phát triển API công khai, bạn không thể kiểm tra cách mọi người sử dụng mã của mình. Tuy nhiên, bạn vẫn có thể xác định hợp đồng cho các phương thức của mình.

Cá nhân tôi sẽ chỉ nghiêm ngặt về các hợp đồng khi giao dịch với API công khai của một mô-đun. Trong nhiều trường hợp khác, nó có thể không đáng để nỗ lực (và bạn có thể sử dụng các bài kiểm tra đơn vị thay thế), nhưng đây chỉ là ý kiến ​​của tôi.

Điều đó không có nghĩa là tôi khuyên bạn không nên nghĩ về hợp đồng trong những trường hợp đó. Tôi luôn nghĩ về họ. Tôi chỉ không nghĩ rằng cần phải luôn luôn mã hóa chúng một cách rõ ràng.


1

Như đã đề cập Hợp đồng và thử nghiệm đơn vị có mục đích khác nhau.

Hợp đồng là về lập trình phòng thủ để đảm bảo rằng các điều kiện tiên quyết được đáp ứng, mã được gọi với các tham số đúng, v.v.

Các thử nghiệm đơn vị để đảm bảo rằng mã hoạt động, trong các kịch bản differnt. Chúng giống như 'thông số kỹ thuật với răng'.

Khẳng định là tốt họ làm cho mã mạnh mẽ. Tuy nhiên, nếu bạn lo lắng rằng nó đang thêm rất nhiều mã, bạn cũng có thể muốn thêm các điểm dừng có điều kiện tại một số nơi trong quá trình gỡ lỗi và giảm số lượng Assert.


0

Bất cứ điều gì bạn có trong các cuộc gọi checkVariants () của bạn đều có thể được thực hiện từ thử nghiệm, bao nhiêu nỗ lực thực sự có thể phụ thuộc vào nhiều thứ (phụ thuộc bên ngoài, mức độ khớp nối, v.v.) nhưng nó sẽ làm sạch mã theo một quan điểm. Làm thế nào kiểm chứng được một cơ sở mã được phát triển dựa trên các xác nhận sẽ không có một số cấu trúc lại mà tôi không chắc chắn.

Tôi đồng ý với @duros, những điều này không nên được coi là phương pháp tiếp cận độc quyền hoặc cạnh tranh. Trong thực tế trong môi trường TDD, bạn thậm chí có thể lập luận rằng các xác nhận 'yêu cầu' sẽ cần phải có các xét nghiệm :).

Tuy nhiên, các xác nhận KHÔNG làm cho mã mạnh hơn trừ khi bạn thực sự làm gì đó để sửa lỗi kiểm tra không thành công, chúng chỉ dừng dữ liệu bị hỏng hoặc tương tự, thường là bằng cách hủy xử lý ở dấu hiệu rắc rối đầu tiên.

Một giải pháp được kiểm tra / kiểm tra tốt thường sẽ nghĩ về và / hoặc phát hiện ra nhiều nguồn / lý do của đầu vào và đầu ra xấu trong khi phát triển các thành phần tương tác và đã xử lý chúng gần hơn với nguồn của vấn đề.

Nếu nguồn của bạn là bên ngoài và bạn không có quyền kiểm soát nó thì để tránh làm lộn xộn mã của bạn xử lý các vấn đề về mã khác, bạn có thể xem xét triển khai một số loại thành phần làm sạch / xác nhận dữ liệu ở giữa nguồn và thành phần của bạn và đặt kiểm tra của bạn vào đó .

Ngoài ra, tôi tò mò về những ngôn ngữ mà bạn sử dụng không có xUnit hoặc thư viện thử nghiệm nào khác mà ai đó đã phát triển, tôi nghĩ có gì đó cho mọi thứ ngày nay không?


0

Ngoài các thử nghiệm đơn vị và hợp đồng mã, tôi chỉ nghĩ rằng tôi nhấn mạnh một khía cạnh khác, đó là giá trị trong việc xác định giao diện của bạn để bạn loại bỏ hoặc giảm khả năng gọi mã của bạn không chính xác ngay từ đầu.

Không phải lúc nào cũng dễ dàng hoặc có thể, nhưng chắc chắn đáng để bạn tự đặt câu hỏi, "Tôi có thể làm cho mã này dễ dàng hơn không?"

Anders Hejlsberg, người tạo ra C #, nói rằng một trong những sai lầm lớn nhất trong C # là không bao gồm các loại tham chiếu không thể rỗng. Đó là một trong những lý do chính khiến rất nhiều sự lộn xộn của mã bảo vệ cần thiết tồn tại.

Tuy nhiên, việc tái cấu trúc để chỉ có số lượng mã bảo vệ cần và đủ cần thiết, theo kinh nghiệm của tôi, mã có thể sử dụng và bảo trì nhiều hơn.

Đồng ý với @duros về phần còn lại của nó.


0

Làm cả hai, nhưng thực hiện một số phương pháp trợ giúp tĩnh để làm rõ ý định của bạn. Đây là những gì Google đã làm cho Java, hãy xem code.google.com/p/guava-lologists/wiki/PreconditionsExplained

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.