Làm thế nào tôi có thể đơn vị kiểm tra một lớp yêu cầu một cuộc gọi dịch vụ web?


21

Tôi đang cố gắng kiểm tra một lớp gọi một số dịch vụ web của Hadoop. Mã này có khá nhiều dạng:

method() {
    ...use Jersey client to create WebResource...
    ...make request...
    ...do something with response...
}

ví dụ: có một phương thức tạo thư mục, một phương thức tạo thư mục, v.v.

Cho rằng mã đang xử lý một dịch vụ web bên ngoài mà tôi không có quyền kiểm soát, làm cách nào tôi có thể kiểm tra đơn vị này? Tôi có thể thử và chế nhạo ứng dụng / phản hồi của khách hàng dịch vụ web nhưng điều đó phá vỡ nguyên tắc tôi đã thấy gần đây: "Đừng chế giễu các đối tượng bạn không sở hữu". Tôi có thể thiết lập triển khai dịch vụ web giả - điều đó vẫn tạo thành "thử nghiệm đơn vị" hay sau đó sẽ là thử nghiệm tích hợp? Có phải là không thể kiểm tra đơn vị ở mức thấp này - một học viên TDD sẽ làm thế nào về điều này?


5
Bạn đã thấy hướng dẫn về việc không chế nhạo những thứ mà bạn không sở hữu ở đâu? Đó dường như là một lý do lớn tại sao bạn nên chế giễu mọi thứ ...
Thomas Owens

1
Tôi đã đọc nó trên rất nhiều blog, một trong số đó tham khảo nó trên amazon.com/Growing-Object-Orients-Software-Guided-Tests/dp/iêu mà tôi biết là một cuốn sách được đánh giá cao ( blog.8thlight. com / eric-smith / 2011/10/27 / thats-not-mine.html , mockobjects.com/2007/04/test-smell-everything-is-mocked.html )
Chris Cooper

1
@ChrisCooper: Tôi có thể chỉ ra rằng liên kết cuối cùng đã rất lỗi thời (từ năm 2007). Nhiều thứ đã thay đổi kể từ đó. Tôi có cảm giác từ bài đăng rằng việc chế nhạo trở nên khó khăn hơn rất nhiều khi bạn phải thực sự thực hiện hành vi thay vì chỉ đơn giản là sử dụng khung mô
phỏng

Câu trả lời:


41

Theo tôi, bạn nên chế nhạo các cuộc gọi dịch vụ web nếu đây là thử nghiệm đơn vị, trái ngược với thử nghiệm tích hợp.

Kiểm tra đơn vị của bạn không nên kiểm tra xem dịch vụ web bên ngoài có hoạt động hay không, liệu sự tích hợp của bạn với nó có đúng không. Không quá giáo điều về TDD, lưu ý rằng tác dụng phụ của việc biến bài kiểm tra đơn vị của bạn thành bài kiểm tra tích hợp là nó có khả năng chạy chậm hơn và bạn muốn kiểm tra đơn vị nhanh .

Ngoài ra, nếu dịch vụ web tạm thời ngừng hoạt động hoặc hoạt động không chính xác, điều này có nên khiến bài kiểm tra đơn vị của bạn bị lỗi không? Có vẻ như không đúng. Kiểm tra đơn vị của bạn chỉ nên thất bại vì một lý do: nếu có lỗi trong mã trong "đơn vị" đó.

Phần duy nhất của mã có liên quan ở đây là ...do something with response.... Mock phần còn lại.


2
Hãy nhớ rằng bạn sẽ phải giữ chữ ký đối tượng giả của mình và trả về các giá trị đồng bộ với các giá trị được tạo bởi dịch vụ web Hadoop trong suốt các thay đổi không thể tránh khỏi đối với dịch vụ đó.
pcurry

Rất hiếm khi thử nghiệm các thành phần có sẵn như Hadoop. Nhưng nếu bạn đang gọi một dịch vụ web tùy chỉnh được cung cấp bởi một nhóm hoặc tổ chức khác, bạn có thể muốn viết một bài kiểm tra cho nó để tự vệ. Theo cách đó, khi có sự cố xảy ra, bạn có thể nhanh chóng kiểm tra xem sự cố là mã của bạn hay dịch vụ web. Đây không phải là một bài kiểm tra đơn vị để chạy tự động; đó là một chẩn đoán để chạy khi cần thiết.
kevin cline

@kevincline Tôi hoàn toàn đồng ý về sự cần thiết của các bài kiểm tra mà bạn đề xuất, và thực sự tôi viết chúng trong công việc hàng ngày của mình và đã chứng minh rằng chúng hữu ích. Nhưng theo định nghĩa, chúng không phải là kiểm tra đơn vị, đó là câu hỏi gì về vấn đề này :) Hãy xem xét điều này: nếu đó là kiểm tra đơn vị và mã không thành công vì dịch vụ web đã bị thay đổi, "đơn vị" mà bạn đang kiểm tra là gì? Chính xác thì thất bại là gì? Bạn không thử nghiệm trong sự cô lập, khi cần thiết bởi thử nghiệm đơn vị.
Andres F.

1
@AndresF.: Tôi nghĩ rằng chúng tôi đang có thỏa thuận bạo lực: "[chẩn đoán] này KHÔNG phải là thử nghiệm đơn vị ..."
kevin cline

@kevincline Đúng rồi! Tôi đọc sai nhận xét của bạn, xin lỗi!
Andres F.

5

Tôi không đồng ý với "không chế nhạo các đối tượng mà bạn không sở hữu" khi bạn đang thử nghiệm đơn vị.

Mục đích của sự tồn tại là thực tế rằng sẽ có các mô-đun, thư viện, các lớp chúng ta sẽ không sở hữu.

Đề nghị của tôi cho kịch bản của bạn là chế nhạo cuộc gọi dịch vụ web.

Thiết lập giả theo cách nó trả dữ liệu trở lại mô-đun của bạn.
Hãy chắc chắn rằng bạn bao gồm tất cả các kịch bản, ví dụ như khi dữ liệu được trả về là null, khi dữ liệu được trả về là hợp lệ, v.v.

Và đối với mã mà bạn sở hữu, trách nhiệm của bạn với tư cách là nhà phát triển là đảm bảo rằng mã bạn đang tác giả thực hiện như mong đợi trong tất cả các kịch bản.


1

Tôi sẽ sử dụng một cái gì đó như EasyMock cho thử nghiệm này. Khung mô phỏng là một cách lý tưởng để loại bỏ các phụ thuộc bên ngoài vào một lớp và cung cấp cho bạn toàn quyền kiểm soát kết quả của các phụ thuộc bên ngoài trong các thử nghiệm. Để mở rộng ví dụ của bạn một chút:

class WebClass {

private WebServiceInterface webserviceInterface;

    void method(){
        R result = webServiceInterface.performWebServiceCall();
        ... do something with result
    }

    public void setWebServiceInterface(WebServiceInterface webServiceInterface){
        this.webServiceInterface = webServiceInterface;
    }
}


interface WebServiceInterface {

   R performWebServiceCall();

}


class WebClassTest {

private WebServiceInterface mock;    
private R sampleResult = new R();

    @Before
    public void before(){
        mock = EasyMock.createMock(WebServiceInterface.class);
    }


    @Test
    public void test() {
        WebClass classUnderTest = new WebClass();
        EasyMock.expect(mock.performWebServiceCall()).andReturn(sampleResult);
        classUnderTest.setWebServiceInterface(mock);
        classUnderTest.method();
        EasyMock.verify(mock);
    }
}

Điều đầu tiên bạn cần làm là trích xuất logic trong lớp của bạn nơi bạn sử dụng Jersey để lấy WebResource và gọi dịch vụ web thành một lớp riêng biệt. Tạo một Giao diện cho lớp này sẽ cho phép bạn tạo một bản giả mà sau đó bạn có thể ra lệnh cho hành vi.

Khi giao diện này được tạo, bạn có thể tạo một bản giả bằng EasyMock, nó sẽ trả về một đối tượng được chỉ định tích lũy vào trường hợp thử nghiệm của bạn. Ví dụ trên là đơn giản hóa cách cấu trúc một bài kiểm tra giả cơ bản và cách giao diện của bạn sẽ hoạt động.

Để biết thêm thông tin về khung mô phỏng , xin vui lòng xem câu hỏi này . Ngoài ra, ví dụ này giả định việc sử dụng Java nhưng các khung mô phỏng có sẵn trong tất cả các ngôn ngữ và mặc dù chúng được triển khai khác nhau, nhưng chúng sẽ hoạt động theo cùng một cách


1

Giả được chấp nhận trong trường hợp này, nhưng bạn không cần nó. Thay vì kiểm tra đơn vị method(), thay vì kiểm tra đơn vị chỉ là phần xử lý phản hồi.

Trích xuất một hàm lấy ResponseData(bất kỳ loại nào là phù hợp) và sau đó thực hiện hành động.

Thay vì chế giễu, bây giờ bạn chỉ cần xây dựng một đối tượng FeedbackData và truyền nó vào.

Bạn có thể để lại cuộc gọi của dịch vụ cho các thử nghiệm tích hợp đầy đủ - sẽ bao gồm method()toàn bộ


0

Những gì tôi đã làm, và nó hoạt động:

  1. Có tất cả các mã gọi dịch vụ web thông qua proxy.
  2. Proxy gọi một lớp mà tĩnh biết chúng ta có đang sử dụng proxy hay không và chuyển hướng tương ứng. Giả chỉ là HashMaps mà cho mỗi yêu cầu trả về một câu trả lời nhất định.
  3. Chạy thử nghiệm nhiều lần theo thứ tự này:

3.1 Đầu tiên tất cả các dịch vụ web được kiểm tra. Từ mỗi máy, thậm chí cả máy của nhà phát triển. Đây là các dịch vụ web thực sự, nhưng đang chạy trong môi trường phát triển. Điều này có nghĩa là dịch vụ web không bao giờ có thể bị hỏng hoặc trả lời các giá trị sai lầm, bởi vì nếu không thì mọi nhà phát triển đều phàn nàn rằng anh ta không thể biên dịch.

3.2 Sau đó, tất cả các bài kiểm tra đơn vị nội bộ cho ứng dụng được chạy. Điều này có nghĩa là tất cả các dịch vụ web đều bị chế giễu và thử nghiệm chạy các thử nghiệm tương tự như 3.1 (anbde họ cũng nên vượt qua, nếu không thì giả lập là sai) và được ứng dụng thực sự gọi như thể chúng đang được sử dụng. Nếu các giả định sai, bạn có thể chạy thử nghiệm trong 3.1 và ghi lại các giá trị (yêu cầu, trả lời) đó trong HashMap.

3.3 Sau đó, các thử nghiệm tương tự như 3.2 được chạy, nhưng lần này đối với các dịch vụ web thực sự đang chạy trong môi trường phát triển.

Sau khi tất cả những điều này đã được hoàn thành, đối với môi trường sản xuất thực, bạn chỉ cần cung cấp địa chỉ thực cho mỗi dịch vụ web. Hy vọng rằng điều này không đòi hỏi quá nhiều thay đổi trong cấu hình.

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.