代码之家  ›  专栏  ›  技术社区  ›  Ian Ringrose

使用Rhino Mocks,我如何拦截对接口上单个属性的调用,同时将其他所有内容传递给默认实现?

  •  4
  • Ian Ringrose  · 技术社区  · 14 年前

    许多的 方法和属性,我希望创建一个mock,使Config属性返回我选择的对象,同时将所有其他调用传递到IComplex的实际实例。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Stefan Steinegger    14 年前

    据我所知,没有一个特性可以同时配置许多mock方法。您需要指定所有方法以将它们转发到其他实现。。。

    ... 除非您编写一些反射代码来配置模拟。

    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);
        }
    }
    
        2
  •  1
  •   Pieter van Ginkel    14 年前

    你可以使用 PartialMock 方法来创建模拟。

    注意,您要模拟的方法 IComplex

    http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx 更多信息。

        3
  •  1
  •   Wim Coenen    14 年前

    据我所知,犀牛嘲笑不支持这一点。但是,您可以使用 Castle Dynamic Proxy 图书馆。(Rhino mocks使用相同的库。)