Feel Good.

31 августа 2011

Mock для ICloneable типов

Буквально недавно я столкнулся с задачей, суть которой заключалась в том, чтобы создать mock объект реализующий интерфейс ICloneable, например средствами Moq.
В моей ситуации, было все просто: метод Clone должен возвращать объект (которого на самом деле нет), с наперед известными данными (которые не подлежали бы изменениям). Для наглядности лучше привести исходный код.
Пусть это будет следующий интерфейс:

public interface ISome : ICloneable

{

    // некое бизнес-поле

    int Value { get; }

}

И для этого интерфейса, построим mock объект реализующий его.
Итак, тесты вперед, поэтому напишем простой unit-test для метода Clone:

[TestMethod]

public void CloneTest()

{

    var original = MakeMockCloneableSome();

 

    // покажем, что и у клонированого объекта

    // метод Clone работает как надо

    var clone = (ISome)((ISome)((ISome)original.Clone()).Clone()).Clone();

 

    // проверим, что бизнес поле совпадает

    Assert.AreEqual(original.Value, clone.Value);

 

    // проверим, что это 2 отдельных объекта

    Assert.IsFalse(Object.ReferenceEquals(original, clone));

}

В тесте я трижды вызывают метод Clone для того, чтобы продемонстрировать, что и у клонированного объекта метод Clone тоже работает, это важно.
Осталось реализовать метод MakeMockCloneableSome():

ISome MakeMockCloneableSome()

{

    var mock = new Mock<ISome>();

 

    // Здесь привычный нам mock бизнес логики...

    mock

        .Setup(c => c.Value)

        .Returns(123);

 

    // Искомый mock метода ICloneable.Clone()

    mock

        .Setup(c => c.Clone())

        .Returns(MakeMockCloneableSome);

 

    return mock.Object;

}