Làm thế nào để MOQ một thuộc tính được lập chỉ mục


81

Tôi đang cố gắng bắt chước một cuộc gọi đến một thuộc tính được lập chỉ mục. Tức là tôi muốn moq như sau:

object result = myDictionaryCollection["SomeKeyValue"];

và cả giá trị setter

myDictionaryCollection["SomeKeyValue"] = myNewValue;

Tôi đang làm điều này vì tôi cần mô phỏng chức năng của một lớp mà ứng dụng của tôi sử dụng.

Có ai biết làm thế nào để làm điều này với MOQ? Tôi đã thử các biến thể sau:

Dictionary<string, object> MyContainer = new Dictionary<string, object>();
mock.ExpectGet<object>( p => p[It.IsAny<string>()]).Returns(MyContainer[(string s)]);

Nhưng điều đó không biên dịch.

Liệu những gì tôi đang cố gắng đạt được với MOQ, có ai có ví dụ nào về cách tôi có thể làm được điều này không?


Sẽ không dễ dàng hơn nếu chỉ sử dụng một đối tượng sơ khai? Đặt các giá trị cần thiết và kiểm tra các chỉ mục bạn cần.
Søren Spelling Lund

Câu trả lời:


94

Không rõ bạn đang cố gắng làm gì vì bạn không hiển thị tuyên bố của mô hình. Bạn đang cố gắng chế nhạo một cuốn từ điển?

MyContainer[(string s)] C # không hợp lệ.

Điều này biên dịch:

var mock = new Mock<IDictionary>();
mock.SetupGet( p => p[It.IsAny<string>()]).Returns("foo");

1
điều này cũng hoạt động. ngoại trừ cú pháp mới sử dụng SetupSetthay thế ExpectGet. cũng hoạt động cho các setters.
tmont

1
Các IDictionary là từ System.Collections và không phải từ System.Collections.Generic
upInCloud

20

Ash, nếu bạn muốn có mô hình Phiên HTTP, thì đoạn mã này sẽ thực hiện công việc:

/// <summary>
/// HTTP session mockup.
/// </summary>
internal sealed class HttpSessionMock : HttpSessionStateBase
{
    private readonly Dictionary<string, object> objects = new Dictionary<string, object>();

    public override object this[string name]
    {
        get { return (objects.ContainsKey(name)) ? objects[name] : null; }
        set { objects[name] = value; }
    }
}

/// <summary>
/// Base class for all controller tests.
/// </summary>
public class ControllerTestSuiteBase : TestSuiteBase
{
    private readonly HttpSessionMock sessionMock = new HttpSessionMock();

    protected readonly Mock<HttpContextBase> Context = new Mock<HttpContextBase>();
    protected readonly Mock<HttpSessionStateBase> Session = new Mock<HttpSessionStateBase>();

    public ControllerTestSuiteBase()
        : base()
    {
        Context.Expect(ctx => ctx.Session).Returns(sessionMock);
    }
}

Nice one - đây là chỉ là những gì tôi cần 1
Ian Oxley

1
Phần nào của mã này làm cho mã đang thử nghiệm sử dụng phiên thử nghiệm? Là TestSuiteBasethư viện hay lớp học của riêng bạn?
StuperUser

Đó không phải là giả, mà là giả. Chỉ nói.
Chris Peacock

17

Như bạn đã phát hiện chính xác, có các phương pháp riêng biệt SetupGetSetupSetđể khởi tạo getters và setters tương ứng. Mặc dù SetupGetđược thiết kế để sử dụng cho các thuộc tính, không phải cho các chỉ mục và sẽ không cho phép bạn xử lý khóa được chuyển đến nó. Nói một cách chính xác, đối với người lập chỉ mục SetupGetvẫn sẽ gọi Setup:

internal static MethodCallReturn<T, TProperty> SetupGet<T, TProperty>(Mock<T> mock, Expression<Func<T, TProperty>> expression, Condition condition) where T : class
{
  return PexProtector.Invoke<MethodCallReturn<T, TProperty>>((Func<MethodCallReturn<T, TProperty>>) (() =>
  {
    if (ExpressionExtensions.IsPropertyIndexer((LambdaExpression) expression))
      return Mock.Setup<T, TProperty>(mock, expression, condition);
    ...
  }
  ...
}

Để trả lời câu hỏi của bạn, đây là một mẫu mã sử dụng cơ bản Dictionaryđể lưu trữ các giá trị:

var dictionary = new Dictionary<string, object>();

var applicationSettingsBaseMock = new Mock<SettingsBase>();
applicationSettingsBaseMock
    .Setup(sb => sb[It.IsAny<string>()])
    .Returns((string key) => dictionary[key]);
applicationSettingsBaseMock
    .SetupSet(sb => sb["Expected Key"] = It.IsAny<object>())
    .Callback((string key, object value) => dictionary[key] = value);

Như bạn có thể thấy, bạn phải chỉ định rõ ràng khóa để thiết lập bộ lập chỉ mục. Chi tiết được mô tả trong một câu hỏi SO khác: Moq một thuộc tính được lập chỉ mục và sử dụng giá trị chỉ mục trong trả về / gọi lại


1
Đây là những gì tôi đang tìm kiếm !! Không ai trong số những ví dụ khác làm việc
Fiona - myaccessible.website

8

Nó không khó lắm nhưng phải mất một chút để tìm nó :)

var request = new Moq.Mock<HttpRequestBase>();
request.SetupGet(r => r["foo"]).Returns("bar");

-4

Có vẻ như những gì tôi đang cố gắng làm với MOQ là không thể.

Về cơ bản, tôi đang cố gắng MOQ một đối tượng kiểu HTTPSession, trong đó khóa của mục được đặt thành chỉ mục chỉ có thể được xác định trong thời gian chạy. Quyền truy cập vào thuộc tính được lập chỉ mục cần thiết để trả về giá trị đã được đặt trước đó. Điều này hoạt động cho các chỉ mục dựa trên số nguyên, nhưng các chỉ mục dựa trên chuỗi không hoạt động.

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.