С помощью Rhino Mocks, как мне перехватить вызов одного свойства в интерфейсе, передав все остальное «реализации по умолчанию»? - PullRequest
4 голосов
/ 11 ноября 2010

У меня есть интерфейс IComplex с многими методами и свойствами, я хочу создать «макет», который заставит свойство «Config» возвращать объект по моему выбору, передавая все другие вызовы на «настоящий »экземпляр IComplex.

Чтобы сделать это немного сложнее, мы все еще используем C # V2!

Ответы [ 3 ]

3 голосов
/ 11 ноября 2010

Насколько я знаю, нет функции, позволяющей настраивать много методов макета одновременно.Вам нужно указать все методы, чтобы перенаправить их в другую реализацию ...

... если только вы не напишите некоторый код отражения для настройки макета.

Вот некоторый (рабочий) код,Он использует C # 3.0, но основная часть - это материал Rhino Mocks «старого стиля», который был написан для C # 2.0.

public static class MockExtensions
{

    public static void ForwardCalls<T>(this T mock, T original)
    {
        mock.BackToRecord();
        Type mockType = typeof(T);
        var methods = mockType.GetMethods(BindingFlags.Public | BindingFlags.Instance)
            .Union(mockType.GetInterfaces().SelectMany(x => x.GetMethods(BindingFlags.Public | BindingFlags.Instance)));
        foreach (MethodInfo method in methods)
        {
            List<object> args = new List<object>();
            foreach (var arg in method.GetParameters())
            {
                args.Add(CreateDefaultValue(arg.ParameterType));
            }
            method.Invoke(mock, args.ToArray());
            var myMethod = method;
            if (method.ReturnType == typeof(void))
            {
                LastCall
                    .IgnoreArguments()
                    // not Repeat.Any to allow overriding the value
                    .Repeat.Times(int.MaxValue)
                    .WhenCalled(call => myMethod.Invoke(original, call.Arguments));
            }
            else
            {
                LastCall
                    .IgnoreArguments()
                    // not Repeat.Any to allow overriding the value
                    .Repeat.Times(int.MaxValue)
                    .WhenCalled(call => call.ReturnValue = myMethod.Invoke(original, call.Arguments))
                    .Return(CreateDefaultValue(myMethod.ReturnType));
            }
        }
        mock.Replay();
    }

    private static object CreateDefaultValue(Type type)
    {

        if (type.IsValueType)
        {
            return Activator.CreateInstance(type);
        }
        else
        {
            return Convert.ChangeType(null, type);
        }
    }

}

Использование:

[TestClass]
public class TestClass()
{
    [TestMethod]
    public void Test()
    {
        var mock = MockRepository.GenerateMock<IList<int>>();
        List<int> original = new List<int>();

        mock.ForwardCalls(original);

        mock.Add(7);
        mock.Add(8);
        Assert.AreEqual(2, mock.Count);
        Assert.AreEqual(7, mock[0]);
        Assert.AreEqual(8, mock[1]);

        //fake Count after ForwardCalls, use Repeat.Any()
        mock.Stub(x => x.Count)
            .Return(88)
            .Repeat.Any(); // repeat any needed to "override" value

        // faked count
        Assert.AreEqual(88, mock.Count);
    }
}
1 голос
/ 11 ноября 2010

Вы хотите создать прокси-объект, который передает все вызовы экземпляру реальной реализации, за исключением случаев, когда вы хотите переопределить поведение члена.поддержать это.Тем не менее, вы можете создать такую ​​же функцию с помощью библиотеки Castle Dynamic Proxy .(Носорог использует ту же библиотеку.)

1 голос
/ 11 ноября 2010

Вы можете использовать метод PartialMock для создания макета.

Вы передаете тип реального класса этому методу и регистрируете только те вызовы, которые вам нужно смоделировать.

Обратите внимание, что методы, которые вы хотите использовать для реализации IComplex, должны быть виртуальными для достижения этой цели.

См. http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx для получения дополнительной информации.

...