Bạn có thể giúp tôi hiểu về Moq Callback?


95

Sử dụng Moq và xem xét Callback nhưng tôi không thể tìm thấy một ví dụ đơn giản để hiểu cách sử dụng nó.

Bạn có một đoạn mã làm việc nhỏ giải thích rõ ràng cách thức và thời điểm sử dụng nó không?

Câu trả lời:


82

Khó đánh bại https://github.com/Moq/moq4/wiki/Quickstart

Nếu điều đó không đủ rõ ràng, tôi sẽ gọi đó là lỗi tài liệu ...

CHỈNH SỬA: Để đáp lại sự làm rõ của bạn ...

Đối với mỗi phương pháp chế nhạo Setupbạn thực hiện, bạn phải chỉ ra những điều như:

  • ràng buộc về đầu vào
  • giá trị cho / cách mà giá trị trả về (nếu có) sẽ được tính

.Callbackchế nói rằng "Tôi không thể mô tả nó ngay bây giờ, nhưng khi một cuộc gọi có hình dạng như thế này xảy ra, hãy gọi lại cho tôi và tôi sẽ làm những gì cần phải làm". Là một phần của cùng một chuỗi cuộc gọi thông thạo, bạn có thể kiểm soát kết quả để trả về (nếu có) thông qua .Returns". Trong các ví dụ QS, một ví dụ là chúng làm cho giá trị được trả về tăng lên mỗi lần.

Nói chung, bạn sẽ không cần một cơ chế như thế này thường xuyên (Mẫu thử nghiệm xUnit có các thuật ngữ cho phản vật chất của Thử nghiệm logic có điều kiện ilk), và nếu có bất kỳ cách nào đơn giản hơn hoặc có sẵn để thiết lập những gì bạn cần, nó sẽ được sử dụng trong sở thích.

Phần 3 của 4 trong loạt phim Moq của Justin Etheringge đề cập đến nó, và có một ví dụ khác về gọi lại ở đây

Một ví dụ đơn giản về gọi lại có thể được tìm thấy tại Sử dụng Gọi lại với bài đăng Moq .


3
Xin chào Ruben Tôi đang học Moq và nếu bạn thích, tôi sẽ lấy rất nhiều ví dụ để hiểu cách thực hiện mọi thứ bằng cách sử dụng nó. Vấn đề của tôi là tôi không hiểu khi nào thì sử dụng nó. Khi tôi hiểu vấn đề đó đã được giải quyết, tôi sẽ viết mã của riêng mình. cảm ơn đánh giá cao thời gian của bạn
dùng9969

15
Khó đánh bại [liên kết]? Không có gì. Liên kết đó chỉ cho bạn cách thực hiện hàng tá việc khác nhau, nhưng không cho bạn biết lý do tại sao bạn cần làm bất kỳ việc nào trong số đó. Tôi đã tìm thấy đó là một vấn đề phổ biến trong tài liệu chế nhạo. Tôi có thể đếm trên đầu ngón tay số lượng lời giải thích tốt, rõ ràng về việc chế giễu TDD + mà tôi đã tìm thấy. Hầu hết đều giả định một mức độ kiến ​​thức mà nếu tôi có nó, tôi sẽ không cần phải đọc bài báo.
Ryan Lundy

@Kyralessa: Tôi hiểu ý bạn. Cá nhân tôi đã có khá nhiều kiến ​​thức sách vở nên tôi thấy nội dung bắt đầu nhanh hoàn toàn hoàn hảo. Thật không may, tôi không biết một ví dụ tốt hơn mà những cái tôi đã liên kết ở cuối bài đăng. Nếu bạn tìm thấy một cái, hãy đăng nó ở đây và tôi sẽ sẵn lòng chỉnh sửa nó trong (hoặc vui lòng tự làm)
Ruben Bartelink

"Tôi sẽ làm những gì cần làm và cho bạn biết kết quả để trả về (nếu có)" Tôi nghĩ điều này gây hiểu lầm, AFAIU Callbackkhông liên quan gì đến giá trị trả về (trừ khi bạn tình cờ liên kết nó thông qua mã). Về cơ bản, nó chỉ đảm bảo rằng lệnh gọi lại được gọi trước hoặc sau mỗi lần gọi (tùy thuộc vào việc bạn xâu chuỗi nó trước hay sau Returnstương ứng), thuần túy và đơn giản.
Ohad Schneider

1
@OhadSchneider Theo liên kết của tôi ... bạn đã đúng! Tự hỏi (nhưng không thực sự hứng thú vì đã không sử dụng Moq trong một thời gian dài) nếu giao diện Fluent đã thay đổi (dường như không có khả năng xảy ra, tức là tôi đã nhầm lẫn và không đọc nội dung mà tôi đã liên kết như thường lệ. từ tự động hoàn thành). Hy vọng các địa chỉ sửa chữa điểm của bạn, cho tôi biết nếu nó không
Ruben Bartelink

59

Dưới đây là một ví dụ về việc sử dụng một lệnh gọi lại để kiểm tra một thực thể được gửi đến Dịch vụ dữ liệu xử lý phần chèn.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Cú pháp phương pháp chung thay thế:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Sau đó, bạn có thể kiểm tra một cái gì đó như

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");

4
Có thể cho rằng đối với trường hợp cụ thể đó (tùy thuộc vào việc bạn đang cố gắng thể hiện các bài kiểm tra chống lại trạng thái hay hành vi), trong một số trường hợp, có thể sử dụng một It.Is<T>trong một Mock.Verifythay vì xả rác kiểm tra với nhiệt độ. Nhưng +1 vì tôi cá rằng có rất nhiều người sẽ hoạt động tốt nhất từ ​​một ví dụ.
Ruben Bartelink

10

Có hai loại Callbacktrong Moq. Một xảy ra trước khi cuộc gọi trở lại; cái kia xảy ra sau khi cuộc gọi trở lại.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

Trong cả hai lệnh gọi lại, chúng ta có thể:

  1. kiểm tra các đối số của phương pháp
  2. nắm bắt đối số phương pháp
  3. thay đổi trạng thái ngữ cảnh

2
Trên thực tế, cả hai đều xảy ra trước khi cuộc gọi trở lại (theo như người gọi có liên quan). Xem stackoverflow.com/a/28727099/67824 .
Ohad Schneider

5

Callbackchỉ đơn giản là một phương tiện để thực thi bất kỳ mã tùy chỉnh nào bạn muốn khi một lệnh gọi được thực hiện đến một trong các phương thức của mô hình. Đây là một ví dụ đơn giản:

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

Gần đây tôi đã gặp phải một trường hợp sử dụng thú vị cho nó. Giả sử bạn mong đợi một số cuộc gọi đến mô phỏng của mình, nhưng chúng xảy ra đồng thời. Vì vậy, bạn không có cách nào để biết thứ tự mà họ sẽ được gọi, nhưng bạn muốn biết các cuộc gọi mà bạn mong đợi đã diễn ra (bất kể thứ tự). Bạn có thể làm điều gì đó như sau:

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

BTW đừng nhầm lẫn bởi sự phân biệt "trước Returns" và "sau Returns" gây hiểu lầm . Nó chỉ đơn thuần là sự phân biệt kỹ thuật về việc mã tùy chỉnh của bạn sẽ chạy sau khi Returnsđã được đánh giá hay trước đó. Trong mắt của người gọi, cả hai sẽ chạy trước khi giá trị được trả về. Thật vậy, nếu phương thức đang voidquay lại, bạn thậm chí không thể gọi được Returnsvà nó vẫn hoạt động như cũ. Để biết thêm thông tin, hãy xem https://stackoverflow.com/a/28727099/67824 .


1

Ngoài các câu trả lời hay khác ở đây, tôi đã sử dụng nó để thực hiện logic trước khi đưa ra một ngoại lệ. Ví dụ: tôi cần lưu trữ tất cả các đối tượng đã được chuyển cho một phương thức để xác minh sau này và phương thức đó (trong một số trường hợp thử nghiệm) cần phải đưa ra một ngoại lệ. Gọi .Throws(...)về Mock.Setup(...)ghi đè các Callback()hành động và không bao giờ gọi nó. Tuy nhiên, bằng cách đưa ra một ngoại lệ trong Callback, bạn vẫn có thể thực hiện tất cả những thứ tốt mà một callback cung cấp và vẫn có một ngoại lệ.

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.