Liệu nó có ý nghĩa để đo mức độ bao phủ có điều kiện cho mã Java 8?


19

Tôi đang tự hỏi liệu việc đo độ bao phủ mã có điều kiện bằng các công cụ hiện tại cho Java không bị lỗi thời kể từ khi Java 8 xuất hiện. Với Java 8 OptionalStreamchúng ta thường có thể tránh các nhánh / vòng mã, điều này giúp dễ dàng có được phạm vi điều kiện rất cao mà không cần kiểm tra tất cả các đường dẫn thực thi có thể. Hãy so sánh mã Java cũ với mã Java 8:

Trước Java 8:

public String getName(User user) {
    if (user != null) {
        if (user.getName() != null) {
            return user.getName();
        }
    }
    return "unknown";
}

Có 3 đường dẫn thực thi có thể trong phương thức trên. Để có được 100% bảo hiểm có điều kiện, chúng tôi cần tạo 3 bài kiểm tra đơn vị.

Java 8:

public String getName(User user) {
    return Optional.ofNullable(user)
                   .map(User::getName)
                   .orElse("unknown");
}

Trong trường hợp này, các chi nhánh bị ẩn và chúng tôi chỉ cần 1 thử nghiệm để được bảo hiểm 100% và chúng tôi sẽ không kiểm tra trường hợp nào. Mặc dù vẫn còn 3 nhánh logic giống nhau nên được bảo vệ. Tôi nghĩ rằng nó làm cho số liệu thống kê bảo hiểm có điều kiện hoàn toàn không đáng tin cậy những ngày này.

Liệu nó có ý nghĩa để đo mức độ bao phủ có điều kiện cho mã Java 8? Có bất kỳ công cụ khác phát hiện mã được thực hiện?


5
Số liệu bảo hiểm chưa bao giờ là một cách tốt để xác định xem mã của bạn có được kiểm tra tốt hay không, chỉ là một cách để xác định những gì chưa được kiểm tra. Một nhà phát triển giỏi sẽ suy nghĩ thông qua các trường hợp khác nhau trong tâm trí của cô ấy, và đưa ra các bài kiểm tra cho tất cả chúng - hoặc ít nhất là tất cả những gì cô ấy nghĩ là quan trọng.
kdgregory

3
Tất nhiên độ bao phủ có điều kiện cao không có nghĩa là chúng tôi có các bài kiểm tra tốt, nhưng tôi nghĩ rằng đó là lợi thế lớn để biết đường dẫn thực hiện nào được khám phá và đây là câu hỏi chủ yếu là gì. Không có bảo hiểm có điều kiện, sẽ khó hơn nhiều để phát hiện ra các kịch bản chưa được kiểm tra. Về đường dẫn: [user: null], [user: notnull, user.name:null], [user: notnull, user.name:notnull]. Tôi đang thiếu gì?
Karol Lewandowski

6
Hợp đồng là getNamegì? Có vẻ như là nếu usernull, nó sẽ trả về "không xác định". Nếu userkhông phải là null và user.getName()là null, nó sẽ trả về "không xác định". Nếu userkhông phải là null và user.getName()không phải là null, nó sẽ trả về điều đó. Vì vậy, bạn sẽ kiểm tra đơn vị ba trường hợp đó bởi vì đó là những gì hợp đồng getNamenói về. Bạn dường như đang làm điều đó lạc hậu. Bạn không muốn xem các chi nhánh và viết các bài kiểm tra theo những điều đó, bạn muốn viết các bài kiểm tra của mình theo hợp đồng của bạn và đảm bảo hợp đồng được điền đầy đủ. Đó là khi bạn có phạm vi bảo hiểm tốt.
Vincent Savard

1
Một lần nữa, tôi không nói rằng phạm vi bảo hiểm chứng minh mã của tôi đã được kiểm tra một cách hoàn hảo, nhưng đó là công cụ có giá trị TUYỆT VỜI cho tôi thấy những gì tôi chưa kiểm tra chắc chắn. Tôi nghĩ rằng các hợp đồng thử nghiệm không thể tách rời khỏi các đường dẫn thực hiện thử nghiệm (ví dụ của bạn là đặc biệt vì nó liên quan đến cơ chế ngôn ngữ ngầm). Nếu bạn chưa kiểm tra đường dẫn, thì bạn chưa kiểm tra đầy đủ hợp đồng hoặc hợp đồng chưa được xác định đầy đủ.
Karol Lewandowski

2
Tôi sẽ lặp lại quan điểm trước đây của mình: luôn luôn như vậy, trừ khi bạn chỉ giới hạn ở các tính năng ngôn ngữ cơ bản và không bao giờ gọi bất kỳ chức năng nào chưa được sử dụng. Điều đó có nghĩa là không có thư viện của bên thứ ba và không sử dụng SDK.
kdgregory

Câu trả lời:


4

Có công cụ nào đo các nhánh logic có thể được tạo trong Java 8 không?

Tôi không biết về bất kỳ. Tôi đã cố gắng chạy mã bạn có thông qua JaCoCo (còn gọi là EclEmma) để chắc chắn, nhưng nó hiển thị 0 nhánh trong Optionalphiên bản. Tôi không biết bất kỳ phương pháp cấu hình nào để nói khác. Nếu bạn đã cấu hình nó để bao gồm các tệp JDK, về mặt lý thuyết nó sẽ hiển thị các nhánh Optional, nhưng tôi nghĩ sẽ thật ngớ ngẩn khi bắt đầu xác minh mã JDK. Bạn chỉ cần cho rằng nó đúng.

Tuy nhiên, tôi nghĩ rằng vấn đề cốt lõi là nhận ra rằng các nhánh bổ sung mà bạn có trước Java 8, theo một nghĩa nào đó, là các nhánh được tạo ra một cách giả tạo. Rằng chúng không còn tồn tại trong Java 8 chỉ có nghĩa là bây giờ bạn có công cụ phù hợp cho công việc (trong trường hợp này Optional). Trong mã 8 tiền Java, bạn phải viết các bài kiểm tra đơn vị bổ sung để bạn có thể tin tưởng rằng mỗi nhánh mã hoạt động theo cách có thể chấp nhận được - và điều này trở nên quan trọng hơn một chút trong các phần mã không tầm thường như User/ getNamethí dụ.

Trong mã Java 8, thay vào đó, bạn đặt niềm tin vào JDK rằng mã hoạt động chính xác. Như vậy, bạn nên coi Optionaldòng đó giống như các công cụ bao phủ mã xử lý nó: 3 dòng có 0 nhánh. Rằng có các dòng và nhánh khác trong mã dưới đây là điều bạn chưa từng chú ý trước đây, nhưng đã tồn tại mỗi khi bạn sử dụng một cái gì đó như một ArrayListhoặc HashMap.


2
"Rằng chúng không còn tồn tại trong Java 8 ..." - Tôi không thể đồng ý với nó, Java 8 tương thích ngược ifnullvẫn là một phần của ngôn ngữ ;-) Vẫn có thể viết mã theo cách cũ và vượt qua nullngười dùng hoặc người dùng có nulltên. Các thử nghiệm của bạn chỉ cần chứng minh rằng hợp đồng được đáp ứng bất kể phương thức được thực hiện như thế nào. Vấn đề là không có công cụ nào cho bạn biết nếu bạn đã kiểm tra hợp đồng đầy đủ.
Karol Lewandowski

1
@KarolLewandowski Tôi nghĩ những gì Shaz đang nói là nếu bạn tin tưởng cách thức Optional(và các phương pháp liên quan) hoạt động, bạn không còn phải kiểm tra chúng nữa. Không giống như cách bạn đã thử nghiệm if-else: mọi thứ đều iflà một bãi mìn tiềm năng. Optionalvà các thành ngữ chức năng tương tự đã được mã hóa và đảm bảo không làm bạn vấp ngã, vì vậy về cơ bản có một "nhánh" đã biến mất.
Andres F.

1
@AresresF. Tôi không nghĩ Karol đang đề nghị chúng tôi kiểm tra Optional. Giống như ông nói, về mặt logic, chúng ta vẫn nên kiểm tra getName()xử lý các đầu vào khác nhau có thể theo cách chúng ta dự định, bất kể việc thực hiện nó là gì. Thật khó để xác định điều này mà không có công cụ bao phủ mã giúp đỡ theo cách nó sẽ trước JDK8.
Mike Partridge

1
@MikePartridge Có, nhưng vấn đề là điều này không được thực hiện thông qua bảo hiểm chi nhánh. Bảo hiểm chi nhánh là cần thiết khi viết if-elsebởi vì mỗi cấu trúc đó là hoàn toàn đặc biệt. Ngược lại, Optional, orElse, map, vv, tất cả đều đã được thử nghiệm. Các nhánh, thực tế, "tan biến" khi bạn sử dụng các thành ngữ mạnh mẽ hơn.
Andres F.
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.