Không gian tên ẩn danh làm cho mã không thể kiểm chứng


13

Đây là một mã C ++ điển hình:

foo.hpp

#pragma once

class Foo {
public:
  void f();
  void g();
  ...
};

foo.cpp

#include "foo.hpp"

namespace {
    const int kUpperX = 111;
    const int kAlternativeX = 222;

    bool match(int x) {
      return x < kUpperX || x == kAlternativeX;
    }
} // namespace

void Foo::f() {
  ...
  if (match(x)) return;
  ...

Nó trông giống như một mã C ++ thành ngữ đàng hoàng - một lớp, một hàm trợ giúp matchđược sử dụng bởi các phương thức Foo, một số hằng số cho hàm trợ giúp đó.

Và sau đó tôi muốn viết bài kiểm tra.
Sẽ là hoàn toàn hợp lý khi viết một bài kiểm tra đơn vị riêng biệt match, bởi vì nó không tầm thường.
Nhưng nó nằm trong một không gian tên ẩn danh.
Tất nhiên tôi có thể viết một bài kiểm tra sẽ gọi Foo::f(). Tuy nhiên, đây sẽ không phải là một thử nghiệm tốt nếu Foonặng và phức tạp, thử nghiệm như vậy sẽ không cách ly người thử nghiệm khỏi các yếu tố không liên quan khác.

Vì vậy, tôi phải di chuyển matchvà mọi thứ khác ra khỏi không gian tên ẩn danh.

Câu hỏi: điểm nào của việc đưa các hàm và hằng vào không gian tên ẩn danh, nếu điều đó làm cho chúng không thể sử dụng được trong các thử nghiệm?


3
@ BЈовић đọc lại mã - không gian tên ẩn danh nằm trong foo.cpp, không phải tiêu đề! OP dường như hiểu khá rõ rằng bạn không nên đặt không gian tên anon trong một tiêu đề.
amon

Một số ý tưởng trong Đơn vị kiểm tra mã C ++ trong một không gian tên không tên ... nhưng "điểm" là đóng gói là tốt. Xét cho cùng, đó là cùng một vấn đề với các chức năng thành viên riêng: chúng không thể được kiểm tra một cách không cố ý, nhưng bạn không muốn từ bỏ việc ẩn thông tin để kiểm tra đơn vị (ví dụ: stackoverflow.com/a/3676680 / 3535496 ).
manlio

1
Trường hợp của bạn về mặt khái niệm không khác lắm so với trường hợp thử nghiệm (hoặc không thử nghiệm) phương thức riêng tư. Vì vậy, khi bạn tìm kiếm "đơn vị kiểm tra riêng tư" ở đây trên Lập trình viên, bạn sẽ nhận được rất nhiều câu trả lời bạn có thể áp dụng trực tiếp cho trường hợp của mình.
Doc Brown

@DocBrown Tôi không hỏi làm thế nào để kiểm tra các chức năng trong anon. không gian tên. Tôi đang hỏi "tại sao lại đặt mã vào anon. Không gian tên?" (xem văn bản ở cuối câu hỏi). Đổ lỗi cho Ixrec đã thay đổi tiêu đề thành một cái gì đó khác nhau.
Abyx

1
@Abyx: trong những câu trả lời khác mà tôi đã đề cập ở trên, bạn sẽ tìm thấy sự đồng thuận lớn của nhiều chuyên gia ở đây rằng việc thử nghiệm các phương pháp riêng tư friendlà không nên và không nên sử dụng từ khóa cho mục đích đó. rằng nếu một hạn chế cho một phương thức dẫn đến một tình huống mà bạn không thể kiểm tra trực tiếp nữa, điều đó có nghĩa là các phương thức riêng tư không hữu ích.
Doc Brown

Câu trả lời:


7

Nếu bạn muốn kiểm tra đơn vị chi tiết triển khai riêng tư, bạn thực hiện cùng một kiểu né tránh cho các không gian tên không tên như đối với các thành viên lớp riêng tư (hoặc được bảo vệ):

Đột nhập và tiệc tùng.

Trong khi đối với các lớp bạn lạm dụng friend, đối với các không gian tên không tên, bạn lạm dụng cơ #includechế, điều này thậm chí không buộc bạn phải thay đổi mã.
Bây giờ mã kiểm tra của bạn (hoặc tốt hơn chỉ là thứ gì đó để lộ tất cả mọi thứ) nằm trong cùng một TU, không có vấn đề gì.

Lưu ý: Nếu bạn kiểm tra chi tiết triển khai, kiểm tra của bạn sẽ bị hỏng nếu những thay đổi đó. Hãy thực sự chắc chắn chỉ kiểm tra những chi tiết triển khai đó sẽ bị rò rỉ dù thế nào, hoặc chấp nhận rằng thử nghiệm của bạn là phù du bất thường.


6

Hàm trong ví dụ của bạn trông khá phức tạp và có thể tốt hơn để di chuyển nó đến tiêu đề, cho mục đích thử nghiệm đơn vị.

điểm của việc đưa các hàm và hằng vào không gian tên ẩn danh là gì, nếu nó làm cho chúng không thể sử dụng được trong các thử nghiệm?

Để làm cho họ bị cô lập với phần còn lại của thế giới. Và nó không chỉ là các hàm và hằng mà bạn có thể đặt trong không gian tên ẩn danh - nó cũng dành cho các kiểu.

Tuy nhiên, nếu nó làm cho bài kiểm tra đơn vị của bạn rất phức tạp, thì bạn đang làm sai. Trong trường hợp đó, hàm không thuộc về đó. Sau đó là thời gian để tái cấu trúc một chút để làm cho thử nghiệm đơn giản hơn.

Vì vậy, trong không gian tên ẩn danh chỉ nên sử dụng các hàm rất đơn giản, đôi khi các hằng và kiểu (bao gồm cả typedefs) được sử dụng trong đơn vị dịch đó.


5

Sẽ là hoàn toàn hợp lý khi viết một bài kiểm tra đơn vị riêng biệt cho phù hợp, bởi vì nó khá không tầm thường.

Mã mà bạn đã hiển thị matchlà 1-liner khá nhỏ mà không có trường hợp cạnh khó khăn nào, hoặc nó giống như một ví dụ đơn giản? Dù sao, tôi sẽ cho rằng nó được đơn giản hóa ...

Câu hỏi: điểm nào của việc đưa các hàm và hằng vào không gian tên ẩn danh, nếu điều đó làm cho chúng không thể sử dụng được trong các thử nghiệm?

Câu hỏi này là những gì muốn làm cho tôi nhảy vào đây vì Ded repeatator đã cho thấy một cách hoàn toàn tốt để đột nhập và có được quyền truy cập thông qua #includemánh khóe. Nhưng từ ngữ ở đây làm cho nó có vẻ như kiểm tra từng chi tiết triển khai nội bộ của mọi thứ là một loại mục tiêu cuối cùng phổ quát, khi nó cách xa nó.

Mục tiêu của kiểm tra đơn vị thậm chí không phải lúc nào cũng là kiểm tra từng đơn vị chức năng vi mô nhỏ bên trong. Câu hỏi tương tự áp dụng cho các hàm phạm vi tệp tĩnh trong C. Bạn thậm chí có thể làm cho câu hỏi khó trả lời hơn bằng cách hỏi tại sao các nhà phát triển sử dụng pimplstrong C ++, yêu cầu cả hai friendship#includelừa cho hộp trắng, giao dịch dễ dàng kiểm tra chi tiết triển khai để cải thiện thời gian biên dịch, ví dụ

Từ một loại quan điểm thực dụng, nó có thể nghe có vẻ thô thiển nhưng matchcó thể không được thực hiện chính xác với một số trường hợp cạnh khiến nó tăng lên. Tuy nhiên, nếu các lớp bên ngoài duy nhất, Foo, có quyền truy cập đến matchkhông thể nào sử dụng nó trong một cách mà cuộc gặp gỡ những trường hợp cạnh, sau đó nó chứ không phải không liên quan đến tính chính xác của Foorằng matchcó những trường hợp cạnh đó sẽ không bao giờ được gặp trừ khi Foothay đổi, lúc này các bài kiểm tra Foosẽ thất bại và chúng tôi sẽ biết ngay lập tức.

Một suy nghĩ ám ảnh hơn mong muốn kiểm tra từng chi tiết triển khai nội bộ (có lẽ là một phần mềm quan trọng, chẳng hạn) có thể muốn đột nhập và tiệc tùng, nhưng nhiều người không nhất thiết nghĩ rằng đó là ý tưởng tốt nhất, vì nó sẽ tạo ra hầu hết các thử nghiệm giòn có thể tưởng tượng. YMMV. Nhưng tôi chỉ muốn giải quyết từ ngữ của câu hỏi này làm cho nó nghe giống như khả năng kiểm tra mức độ chi tiết-nội bộ-chi tiết-nội bộ-chi tiết này nên là mục tiêu cuối cùng, khi mà ngay cả tư duy kiểm tra đơn vị nghiêm ngặt nhất cũng có thể thư giãn một chút ở đây và tránh x-quang các phần bên trong của mỗi lớp.

Vậy tại sao mọi người định nghĩa các hàm trong không gian tên ẩn danh trong C ++ hoặc dưới dạng các hàm tĩnh phạm vi tệp có liên kết nội bộ trong C, ẩn khỏi thế giới bên ngoài? Và đó chủ yếu là nó: để che giấu chúng khỏi thế giới bên ngoài. Điều đó có một số hiệu ứng từ giảm thời gian biên dịch đến giảm độ phức tạp (những gì không thể truy cập ở nơi khác có thể gây ra vấn đề ở nơi khác) và vv. Có lẽ khả năng kiểm tra các chi tiết thực hiện riêng tư / nội bộ không phải là điều số một trong tâm trí của mọi người khi họ làm điều đó, nói, giảm thời gian xây dựng và che giấu sự phức tạp không cần thiết từ thế giới bên ngoài.


Tôi ước tôi có thể nâng cao điều này mười lần. Là một tiếp tuyến liên quan đến nhiệm vụ quan trọng, phần mềm đảm bảo cao, bạn quan tâm nhiều hơn đến tính chính xác của các chi tiết. Kiểu thành ngữ này cho C ++ không phù hợp với điều đó. Tôi sẽ không sử dụng các tính năng của ngôn ngữ như không gian tên ẩn danh hoặc các mẫu giống như proxy. Tôi sẽ kiểm soát ranh giới của mình một cách thô thiển với các tiêu đề không gian người dùng [được hỗ trợ] và các tiêu đề không gian của nhà phát triển [không được hỗ trợ].
David
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.