2016-10-26 15 views
5

Tôi đang cố gắng thực hiện thử nghiệm đơn vị với googlemock và tiêm phụ thuộc trong C++. Mocks và phụ thuộc tiêm đáng kể dễ dàng kiểm tra mã, nhưng họ rất nhiều dựa vào phương pháp ảo. Mặc dù các lớp trong các ngôn ngữ khác sử dụng các phương thức ảo theo mặc định, nó không phải là trường hợp của C++. Tôi đang sử dụng C++ để tạo ra một khuôn khổ đo lường hiệu suất thấp, vì vậy chỉ cần làm cho mọi lớp đơn thừa kế từ một giao diện (w/các phương thức ảo thuần túy) không phải là một tùy chọn mong muốn.Phun và phụ thuộc vào C++

Cụ thể, tôi đang gặp vấn đề với các lớp học thử nghiệm có chứa bộ sưu tập của các đối tượng như một sau:

struct event_info { /* ... */ }; 

template<typename Event> 
class event_manager { 
public: 
    event_manager(const std::vector<event_info>& events) { 
    std::transform(begin(events), end(events), 
     std::back_inserter(events_), 
     [](const event_info& info) { return Event{info}; }); 
    } 

    void read() { 
    for (auto& e : events_) 
     e.read(); 
    } 

    // ... 

private: 
    std::vector<Event> events_; 
    // ... 
}; 

Để kiểm tra lớp này tôi có thể làm như sau:

class mock_event { 
public: 
    MOCK_METHOD0(read, void()); 
}; 

TEST(event_manager, test) { 
    event_manager<mock_event> manager; 
    // ... 
} 

Nhưng điều này sẽ không hoạt động vì tôi không thể đặt kỳ vọng cho đối tượng giả và đối tượng giả từ googlemock không thể sao chép được (do đó, lệnh gọi tới std::transform không thể biên dịch được).

Để giải quyết vấn đề này, khi thử nghiệm, tôi có thể sử dụng con trỏ thay thế (ví dụ: event_manager<mock_event*>) và chuyển nhà máy đến nhà xây dựng event_manager. Tuy nhiên, điều này sẽ không biên dịch vì các cuộc gọi như e.read() (nó phải là e->read() thay vì khi thử nghiệm).

Sau đó, tôi có thể sử dụng các đặc điểm kiểu để tạo phương thức nếu đưa ra tham chiếu vừa trả về tham chiếu và nếu có con trỏ, thì hãy chọn con trỏ (ví dụ: dereference(e).read()). Tuy nhiên, điều này chỉ tiếp tục thêm tấn phức tạp và nó không giống như một giải pháp tốt (đặc biệt là nếu cần phải được thực hiện để kiểm tra tất cả các lớp có chứa một bộ sưu tập các đối tượng).

Vì vậy, tôi đã tự hỏi liệu có một giải pháp tốt hơn cho điều này, hoặc nó chỉ là chế nhạo và phụ thuộc tiêm không phải là kỹ thuật rất thích hợp cho C + +.

+0

Đây là một câu hỏi hay! Tôi mong chờ câu trả lời. Trong sự hiểu biết của tôi, có lẽ bạn có thể cố gắng sửa đổi 'event_manager' một chút, sử dụng' std :: vector > ', có lẽ điều này giải quyết được vấn đề. Nhưng tôi đã không cố gắng để không chắc chắn nếu nó hoạt động. – Mine

+0

@Mine Sử dụng 'unique_ptr' và một nhà máy (hoặc chỉ thay đổi giao diện cho phép người dùng thêm' unique_ptr ') sẽ hoạt động. Nhưng sau đó tôi cần phải lưu trữ con trỏ trong sản xuất quá (không chỉ trong khi thử nghiệm), và tôi đang tìm một giải pháp để tránh điều đó. – betabandido

+0

Yup, tôi có nghĩa là bạn có thể lưu trữ con trỏ ('unique_ptr') bot cả mã sản xuất và mã thử nghiệm. Đó không phải là một vấn đề. – Mine

Trả lời

1

Tôi giả định rằng bạn đã thực hiện các phép đo hiệu suất phù hợp với một lớp đơn giản mô phỏng trường hợp sử dụng chuẩn của bạn trước khi quyết định ứng dụng của bạn không thể chịu đựng được thông qua chi phí của một con trỏ dereference để thực hiện cuộc gọi hàm ảo.

Nếu bạn đọc tài liệu gmock, chúng có phần "mô phỏng hiệu suất cao" nơi chúng hiển thị cách sử dụng mẫu trong mã sản xuất để cho phép giả lập các chức năng ảo. Tôi nghĩ rằng quy tắc đầu tiên của mã (sản xuất hoặc thử nghiệm) là giữ mã đơn giản nhất có thể, và vì vậy tôi không tin vào việc thay đổi mã sản xuất bằng các mẫu chỉ để có thể kiểm tra nó (mặc dù trên Mặt khác, tôi hoàn toàn thuận lợi để sử dụng TDD như một phê bình và hướng dẫn thiết kế mã sản xuất của tôi).

Như vậy, có vẻ như ứng dụng của bạn cần một khuôn khổ mocking khác, một ứng dụng cho phép thực hiện chế độ nhạo báng ở thời gian liên kết trái ngược với thời gian chạy.

Kiểm tra cpputest và cppumock (https://cpputest.github.io/), có thể giả lập cả hai chức năng tự do C và các phương thức không phải là C++ ảo.

Giá phải trả bằng cpputest/cppumock là nó đòi hỏi nhiều bản mẫu hơn gmock, nhưng nó rất tốt.

+0

Có, đối với một số chức năng ngắn, nó tạo ra sự khác biệt đáng kể. Tôi chắc chắn sẽ có một cái nhìn tại cpputest. – betabandido

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