Mocking là gì?


Câu trả lời:


598

Lời mở đầu: Nếu bạn tra cứu danh từ giả trong từ điển, bạn sẽ thấy rằng một trong những định nghĩa của từ này là một cái gì đó được làm như một sự bắt chước .


Mocking chủ yếu được sử dụng trong thử nghiệm đơn vị. Một đối tượng được thử nghiệm có thể có sự phụ thuộc vào các đối tượng (phức tạp) khác. Để cô lập hành vi của đối tượng bạn muốn thay thế các đối tượng khác bằng các mô phỏng mô phỏng hành vi của các đối tượng thực. Điều này rất hữu ích nếu các đối tượng thực tế là không thực tế để kết hợp vào bài kiểm tra đơn vị.

Nói tóm lại, chế giễu là tạo ra các đối tượng mô phỏng hành vi của các đối tượng thực.


Đôi khi bạn có thể muốn phân biệt giữa chế giễu trái ngược với gốc cây . Có thể có một số bất đồng về chủ đề này nhưng định nghĩa của tôi về sơ khai là một đối tượng mô phỏng "tối thiểu". Sơ khai thực hiện hành vi vừa đủ để cho phép đối tượng được thử nghiệm thực hiện thử nghiệm.

Một bản giả giống như một sơ khai nhưng bài kiểm tra cũng sẽ xác minh rằng đối tượng được kiểm tra gọi bản giả như mong đợi. Một phần của bài kiểm tra là xác minh rằng giả được sử dụng đúng.

Để đưa ra một ví dụ: Bạn có thể khai thác cơ sở dữ liệu bằng cách triển khai cấu trúc trong bộ nhớ đơn giản để lưu trữ các bản ghi. Đối tượng được kiểm tra sau đó có thể đọc và ghi các bản ghi vào sơ đồ cơ sở dữ liệu để cho phép nó thực hiện kiểm tra. Điều này có thể kiểm tra một số hành vi của đối tượng không liên quan đến cơ sở dữ liệu và sơ khai cơ sở dữ liệu sẽ được đưa vào chỉ để cho phép chạy thử.

Thay vào đó, nếu bạn muốn xác minh rằng đối tượng được kiểm tra ghi một số dữ liệu cụ thể vào cơ sở dữ liệu, bạn sẽ phải giả định cơ sở dữ liệu. Thử nghiệm của bạn sau đó sẽ kết hợp các xác nhận về những gì được ghi vào cơ sở dữ liệu giả.


18
Đây là một câu trả lời tốt, nhưng nó không cần thiết hạn chế khái niệm chế giễu đối tượng . Thay thế "đối tượng" bằng "đơn vị" sẽ làm cho nó tổng quát hơn.
Rogério

1
Tôi hiểu sự khác biệt của sơ khai so với giả. Chỉ có điều là nếu bạn đang kiểm tra các trường hợp của mình với một sơ khai và nó đã qua thì bạn không thể kết luận rằng bạn đã sử dụng sơ khai đó do đó bạn không còn cần xác minh nữa?
Mật ong

91

Các câu trả lời khác giải thích mocking là gì. Hãy để tôi hướng dẫn bạn qua nó với các ví dụ khác nhau . Và tin tôi đi, nó thực sự đơn giản hơn nhiều so với bạn nghĩ.

tl; dr Đó là một thể hiện của lớp gốc. Nó có dữ liệu khác tiêm vào, do đó bạn tránh thử nghiệm những phần tiêm và chỉ tập trung vào kiểm tra chi tiết thực hiện các lớp học của bạn / chức năng.

Một ví dụ đơn giản:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Như bạn có thể thấy, tôi không kiểm tra LineA tức là tôi không xác thực các tham số đầu vào. Tôi không xác thực để xem nếu num1, num2 là một số nguyên. Tôi không có khẳng định chống lại điều đó.

Tôi chỉ đang thử nghiệm để xem LineB ( triển khai của tôi ) có đưa ra các giá trị bị chế giễu 1hay không và 5đang làm như tôi mong đợi.

Rõ ràng trong từ thực sự điều này có thể trở nên phức tạp hơn nhiều. Các tham số có thể là một đối tượng tùy chỉnh như Người, Địa chỉ hoặc chi tiết triển khai có thể nhiều hơn một +. Nhưng logic của thử nghiệm sẽ giống nhau.

Ví dụ không mã hóa:

Giả sử bạn đang xây dựng một máy xác định loại và tên thương hiệu của các thiết bị điện tử để bảo mật sân bay. Máy thực hiện điều này bằng cách xử lý những gì nó nhìn thấy bằng camera của nó.

Bây giờ người quản lý của bạn bước vào cửa và yêu cầu bạn kiểm tra đơn vị.

Sau đó, với tư cách là nhà phát triển, bạn có thể mang 1000 đối tượng thực, như MacBook pro, Google Nexus, chuối, iPad, v.v. ra trước nó và kiểm tra xem tất cả có hoạt động không.

Nhưng bạn cũng có thể sử dụng các đối tượng bị chế giễu , như một chiếc MacBook pro trông giống hệt (không có bộ phận bên trong thực sự) hoặc một quả chuối nhựa phía trước nó. Bạn có thể tiết kiệm cho mình từ việc đầu tư vào năm 1000 máy tính xách tay thực tế và mục nát chuối.

Vấn đề là bạn không cố gắng để kiểm tra nếu chuối là giả hay không. Cũng không kiểm tra xem laptop có giả hay không. Tất cả những gì bạn đang làm là kiểm tra xem máy của bạn một khi nó nhìn thấy một quả chuối thì nó sẽ nói not an electronic devicevà đối với MacBook Pro thì nó sẽ nói : Laptop, Apple. Đối với máy, kết quả phát hiện của nó phải giống với điện tử giả / giả và điện tử thật

Logic được đề cập ở trên cũng áp dụng cho kiểm thử đơn vị mã thực tế. Đó là một hàm nên hoạt động tương tự với các giá trị thực bạn nhận được từ đầu vào thực (và tương tác) hoặc bị chế giễugiá trị bạn tiêm trong đơn vị thử nghiệm. Và cũng giống như cách bạn tự cứu mình khỏi việc sử dụng chuối hoặc MacBook thực sự, với các bài kiểm tra đơn vị (và chế giễu), bạn tự cứu mình khỏi phải làm điều gì đó khiến máy chủ của bạn trả lại mã trạng thái 500, 403, 200, v.v. Máy chủ của bạn để kích hoạt 500 chỉ khi máy chủ ngừng hoạt động, trong khi 200 là khi máy chủ hoạt động. Thật khó để chạy 100 bài kiểm tra tập trung vào mạng nếu bạn phải liên tục chờ 10 giây giữa chuyển đổi lên và xuống máy chủ). Vì vậy, thay vào đó bạn tiêm / giả một phản hồi với mã trạng thái 500, 200, 403, v.v. và kiểm tra đơn vị / chức năng của bạn với giá trị được tiêm / giả.

Mã hóa Ví dụ:

Giả sử bạn đang viết một ứng dụng iOS và có các cuộc gọi mạng. Công việc của bạn là kiểm tra ứng dụng của bạn . Để kiểm tra / xác định xem các cuộc gọi mạng có hoạt động như mong đợi KHÔNG PHẢI LÀ TRÁCH NHIỆM CỦA BẠN. Trách nhiệm của một bên khác (nhóm máy chủ) là kiểm tra nó. Bạn phải loại bỏ sự phụ thuộc (mạng) này và tiếp tục kiểm tra tất cả mã của bạn hoạt động xung quanh nó.

Một cuộc gọi mạng có thể trả về các mã trạng thái khác nhau 404, 500, 200, 303, v.v với phản hồi JSON.

Ứng dụng của bạn được cho là hoạt động cho tất cả chúng (trong trường hợp có lỗi, ứng dụng của bạn sẽ ném lỗi dự kiến). Những gì bạn làm với chế độ chế giễu là bạn tạo ra 'tưởng tượng' tương tự như các phản hồi mạng thực '(như mã 200 với tệp JSON) và kiểm tra mã của bạn mà không ' thực hiện cuộc gọi mạng thực và chờ phản hồi mạng của bạn '. Bạn mã hóa thủ công / trả lại phản hồi mạng cho TẤT CẢ các loại phản hồi mạng và xem ứng dụng của bạn có hoạt động như bạn mong đợi không. (bạn không bao giờ giả định / kiểm tra 200 với dữ liệu không chính xác, vì đó không phải là trách nhiệm của bạn, trách nhiệm của bạn là kiểm tra ứng dụng của bạn với 200 chính xác hoặc trong trường hợp 400, 500, bạn kiểm tra xem ứng dụng của bạn có đưa ra lỗi đúng không)

Điều này tạo ra trí tưởng tượng tương tự như thực tế được gọi là chế nhạo.

Để thực hiện việc này, bạn không thể sử dụng mã gốc của mình (mã gốc của bạn không có phản hồi được chèn sẵn, phải không?). Bạn phải thêm một cái gì đó vào nó, tiêm / chèn dữ liệu giả đó thường không cần thiết (hoặc một phần của lớp học của bạn).

Vì vậy, bạn tạo một thể hiện của lớp gốc và thêm bất cứ thứ gì (ở đây là HTTPResponse mạng, dữ liệu HOẶC trong trường hợp không thành công, bạn chuyển đúng errorString, HTTPResponse) bạn cần đến nó và sau đó kiểm tra lớp bị giả .

Câu chuyện dài, chế giễu là để đơn giản hóagiới hạn những gì bạn đang kiểm tra và cũng khiến bạn nuôi những gì một lớp học phụ thuộc vào. Trong ví dụ này, bạn tránh kiểm tra các cuộc gọi mạng mình , và thay vào đó kiểm tra hay không ứng dụng của bạn hoạt động như bạn mong đợi với những kết quả tiêm / phản ứng - do chế giễu lớp

Không cần phải nói, bạn kiểm tra từng phản ứng mạng riêng biệt.


Bây giờ một câu hỏi mà tôi luôn có trong đầu là: Các hợp đồng / điểm kết thúc và về cơ bản là phản hồi JSON của các API của tôi được cập nhật liên tục. Làm thế nào tôi có thể viết bài kiểm tra đơn vị mà xem xét điều này?

Để giải thích rõ hơn về điều này: giả sử mô hình yêu cầu khóa / trường có tên username. Bạn kiểm tra điều này và bài kiểm tra của bạn vượt qua. 2 tuần sau, phụ trợ thay đổi tên của khóa thành id. Bài kiểm tra của bạn vẫn vượt qua. đúng? hay không?

Có phải là trách nhiệm của nhà phát triển phụ trợ để cập nhật các bản giả. Có nên là một phần trong thỏa thuận của chúng tôi rằng họ cung cấp các bản giả được cập nhật?

Câu trả lời cho vấn đề trên là: kiểm tra đơn vị + quy trình phát triển của bạn với tư cách là nhà phát triển phía khách hàng sẽ / sẽ bắt được phản hồi giả định lỗi thời. Nếu bạn hỏi tôi như thế nào? câu trả lời là:

Ứng dụng thực tế của chúng tôi sẽ thất bại (hoặc không thất bại nhưng không có hành vi mong muốn) nếu không sử dụng API cập nhật ... do đó nếu thất bại ... chúng tôi sẽ thay đổi mã phát triển của mình. Điều này một lần nữa dẫn đến các thử nghiệm của chúng tôi thất bại .... mà chúng tôi sẽ phải sửa nó. (Trên thực tế nếu chúng ta thực hiện đúng quy trình TDD, chúng ta sẽ không viết bất kỳ mã nào về trường trừ khi chúng ta viết thử nghiệm cho nó ... và thấy nó thất bại và sau đó đi và viết mã phát triển thực tế cho nó.)

Tất cả điều này có nghĩa là phụ trợ không cần phải nói: đó là chúng tôi đã cập nhật các bản nháp ... cuối cùngcũng xảy ra thông qua việc phát triển / gỡ lỗi mã của bạn. Bởi vì đó là một phần của quá trình phát triển! Mặc dù nếu phụ trợ cung cấp phản hồi giả cho bạn thì điều đó dễ dàng hơn.

Toàn bộ quan điểm của tôi về vấn đề này là (nếu bạn không thể tự động nhận được cập nhật phản ứng API chế giễu rồi) một số tương tác của con người là cần thiết tức là tay bản cập nhật của JSONs và có cuộc họp ngắn để đảm bảo giá trị của họ được cập nhật sẽ trở thành một phần của quá trình của bạn

Phần này được viết nhờ vào một cuộc thảo luận chậm chạp trong nhóm gặp gỡ của chúng tôi


Chỉ dành cho nhà phát triển iOS:

Một ví dụ rất hay về chế giễu là bài nói chuyện theo định hướng Giao thức thực tế này của Natasha Muraschev . Chỉ cần bỏ qua đến phút 18:30, mặc dù các slide có thể không đồng bộ với video thực tế

Tôi thực sự thích phần này từ bảng điểm:

Bởi vì đây là thử nghiệm ... chúng tôi muốn đảm bảo rằng getchức năng từ Gettableđược gọi, bởi vì nó có thể trở lại và về mặt lý thuyết chức năng có thể gán một mảng các mặt hàng thực phẩm từ bất cứ đâu . Chúng ta cần đảm bảo rằng nó được gọi;


3
Ví dụ tuyệt vời, tôi sẽ chỉ thêm rằng trong ví dụ cụ thể này, lớp con đóng vai trò là giả, nhưng ví dụ này cũng sử dụng stubbing. Các phản hồi JSON được mã hóa cứng được coi là các phản hồi còn sơ khai. Tôi chỉ thêm điều này bởi vì có thể khó phân biệt giữa giả và sơ khai, nhưng ví dụ này cho thấy rõ cả hai có thể được sử dụng cùng nhau như thế nào.
dùng344977

Giải thích tuyệt vời, cảm ơn bạn. Một điều chỉnh nhỏ cho câu hỏi về việc thay đổi API. Điều gì xảy ra nếu đó không phải là API của bạn để bạn không tham gia vào quá trình phát triển? Tôi muốn biết khi thư viện khách hàng của tôi bị lỗi.
ThinkDigital

@ThinkDigital Các nhà cung cấp API tốt có ghi chú phát hành tốt và giao tiếp thay đổi đúng cách, nếu bạn không có kênh đó thì có lẽ đã đến lúc bạn ngồi trong một cuộc họp và thảo luận về nó | các nhà phát triển giỏi sẽ luôn xem xét các thay đổi API của phiên bản mới và tránh chỉ nâng cấp phiên bản API. Bạn có phiên bản API? Nếu không ai trong số họ bắt được nó thì khi QAing bạn sẽ tìm ra, thì hãy cập nhật nhiệm vụ ← của bạn trong toàn đội. → nhiệm vụ một dev duy nhất: không nên quan tâm nhiều. Chỉ xử lý trường hợp máy chủ trả về lỗi hoặc máy chủ không trả về lỗi nhưng không thể phân tích cú pháp hoặc xử lý trường hợp chính xác.
Mật ong

Cảm ơn đã phản hồi, @Honey! Trong trường hợp của tôi, tôi đang duy trì một ứng dụng khách cho pub.dev , có API, nhưng nó thiếu trầm trọng. Vì vậy, tốt hơn là tạo ra một API bằng cách quét trang web của họ, hơn là sử dụng API chính thức của họ. Vì điều này, các thay đổi đối với trang web có thể phá vỡ mã và họ sẽ không cần phải cập nhật bất cứ ai trong trường hợp này. Trang web này là mã nguồn mở, nhưng Đó là một điều khác nhau duy trì một API mà dựa tắt của những thay đổi được thực hiện trên cơ sở tầm thường hơn.
ThinkDigital

32

Có rất nhiều câu trả lời về SO và những bài viết hay trên web về chế giễu. Một nơi mà bạn có thể muốn bắt đầu tìm kiếm là bài đăng của Martin Fowler Mocks Ar't Stub nơi ông thảo luận về rất nhiều ý tưởng chế giễu.

Trong một đoạn - Mocking là một kỹ thuật chi tiết để cho phép thử nghiệm một đơn vị mã mà không phụ thuộc vào các phụ thuộc. Nói chung, điểm khác biệt của việc nhạo báng với các phương thức khác là các đối tượng giả được sử dụng để thay thế phụ thuộc mã sẽ cho phép đặt kỳ vọng - một đối tượng giả sẽ biết cách gọi mã của bạn và cách phản hồi.


Câu hỏi ban đầu của bạn đã đề cập đến TypeMock, vì vậy tôi đã để lại câu trả lời của mình cho câu hỏi dưới đây:

TypeMock là tên của một khung mô phỏng thương mại .

Nó cung cấp tất cả các tính năng của các khung mô phỏng miễn phí như RhinoMocks và Moq, cùng với một số tùy chọn mạnh mẽ hơn.

Cho dù bạn có cần TypeMock hay không vẫn còn gây tranh cãi - bạn có thể thực hiện hầu hết các chế độ chế giễu mà bạn muốn với các thư viện chế giễu miễn phí, và nhiều ý kiến ​​cho rằng các khả năng do TypeMock cung cấp thường sẽ đưa bạn ra khỏi thiết kế được đóng gói tốt.

Như một câu trả lời khác đã nêu 'TypeMocking' thực sự không phải là một khái niệm xác định, nhưng có thể được hiểu là kiểu chế nhạo mà TypeMock đưa ra, sử dụng trình lược tả CLR để chặn .Net gọi trong thời gian chạy, mang lại khả năng lớn hơn cho các đối tượng giả (không phải yêu cầu chẳng hạn như cần giao diện hoặc phương thức ảo).


@Masoud không bao giờ đề cập đến TypeMock. Câu hỏi của anh ấy là về "kiểu nhạo báng" nói chung.
Peter Lillevold

4
@Peter - như một bình luận khác đã nói, hãy kiểm tra lịch sử chỉnh sửa của câu hỏi. Tôi không thể làm gì nhiều nếu tôi đăng câu trả lời và sau đó câu hỏi ban đầu đã hoàn toàn thay đổi.
Hội trường David

9

Mock là một phương thức / đối tượng mô phỏng hành vi của một phương thức / đối tượng thực theo các cách được kiểm soát. Đối tượng giả được sử dụng trong thử nghiệm đơn vị.

Thường thì một phương thức trong một thử nghiệm gọi các dịch vụ hoặc phương thức bên ngoài khác trong đó. Chúng được gọi là phụ thuộc. Sau khi bị chế giễu, các phụ thuộc hành xử theo cách chúng ta định nghĩa chúng.

Với sự phụ thuộc được kiểm soát bởi các giả, chúng ta có thể dễ dàng kiểm tra hành vi của phương thức mà chúng ta đã mã hóa. Đây là bài kiểm tra đơn vị.

Mục đích của các đối tượng giả là gì?

Mocks vs cuống

Kiểm tra đơn vị so với kiểm tra chức năng


7

Mocking đang tạo ra các đối tượng giả mô phỏng hành vi của các đối tượng thực để kiểm tra


5

Mục đích của các loại chế nhạo là cắt đứt các phụ thuộc để cô lập thử nghiệm với một đơn vị cụ thể. Sơ khai là những người thay thế đơn giản, trong khi giả là người thay thế có thể xác minh việc sử dụng. Khung mô phỏng là một công cụ sẽ giúp bạn tạo ra các sơ khai và giả.

EDIT : Kể từ khi từ ngữ ban đầu đề cập đến "kiểu nhạo báng", tôi có ấn tượng rằng điều này liên quan đến TypeMock. Theo kinh nghiệm của tôi các thuật ngữ chung chỉ là "chế giễu". Xin vui lòng bỏ qua thông tin dưới đây cụ thể trên TypeMock.

TypeMock Isolator khác với hầu hết các khung mô phỏng khác ở chỗ nó hoạt động việc sửa đổi IL của tôi một cách nhanh chóng. Điều đó cho phép nó giả định các loại và trường hợp mà hầu hết các khung công tác khác không thể giả định. Để chế nhạo các loại / trường hợp này với các khung khác, bạn phải cung cấp các tóm tắt của riêng bạn và giả định các kiểu này.

TypeMock cung cấp tính linh hoạt cao với chi phí của môi trường thời gian chạy sạch. Là một tác dụng phụ của cách TypeMock đạt được kết quả của nó, đôi khi bạn sẽ nhận được kết quả rất lạ khi sử dụng TypeMock.


@Masoud không bao giờ đề cập đến TypeMock. Câu hỏi của anh ấy là về "kiểu nhạo báng" nói chung.
Peter Lillevold

1
@Peter: Từ ngữ ban đầu là "kiểu nhạo báng là gì?".
Brian Rasmussen

Tôi biết. Vì "gõ mô phỏng" không tương đương với "TypeMock", tôi thấy cả câu trả lời của bạn và @Oded đều không đúng.
Peter Lillevold

1
@Peter: Theo kinh nghiệm của tôi, thuật ngữ chung là "chế giễu", nhưng trong mọi trường hợp tôi đã cập nhật câu trả lời của mình để hy vọng làm rõ điều đó. Cảm ơn các đầu vào.
Brian Rasmussen

3

Tôi nghĩ rằng việc sử dụng khung mô phỏng bộ cách ly TypeMock sẽ là TypeMocking.

Nó là một công cụ tạo ra các giả để sử dụng trong các bài kiểm tra đơn vị, mà không cần phải viết mã của bạn với IoC trong tâm trí.


@Masoud không bao giờ đề cập đến TypeMock. Câu hỏi của anh ấy là về "kiểu nhạo báng" nói chung.
Peter Lillevold

3
Trên thực tế, câu hỏi ban đầu bao gồm từ "Loại" trước "Mocking", nhưng sau đó nó đã được chỉnh sửa. Đó là lý do tại sao một số câu trả lời chứa thông tin cụ thể về TypeMock.
Martin Liversage

1

Nếu giả của bạn liên quan đến một yêu cầu mạng, một lựa chọn khác là có một máy chủ thử nghiệm thực sự để đánh. Bạn có thể sử dụng dịch vụ này để tạo yêu cầu và phản hồi cho thử nghiệm của mình. http://testerurl.com/


Tôi vừa thử truy cập nó, và mất vài phút. Ai sẽ nói đó không phải là bí mật đăng nhập yêu cầu? Cuối cùng, điều này có thể tốt hơn khi bình luận :)
Kieren Johnstone

Tôi thực sự đã gỡ nó xuống vì tôi không muốn chuyển nó sang một dịch vụ lưu trữ miễn phí. vâng, điều này cần phải có được một nhận xét. nó là nguồn mở, vì vậy nếu có mối quan tâm về các yêu cầu ghi nhật ký, bạn có thể tự chạy. github.com/captainchung/TesterUrl
Matthew Chung
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.