使用 Rhino Mock 报告被调用的函数

Use Rhino Mock to report the function that was called

我有一个依赖外部模块的失败测试用例。 我想使用 Rhino Mock 生成有关调用函数的报告。

我创建了一个最小示例来说明我的问题:

using NUnit.Framework;
using Rhino.Mocks;
using System;

namespace Whosebug_namespace
{
    public interface IUsefulService
    {
        object HiddenAmongManyCalls();
    }

    public class ThirdPartyBase
    {
        private int a = 42;

        public ThirdPartyBase(IUsefulService service)
        {
            object liveFastDieYoung = service.HiddenAmongManyCalls();
            liveFastDieYoung.Equals(a);
        }
    }

    public class MyParty : ThirdPartyBase
    {
        public MyParty(IUsefulService service) : base(service)
        {

        }
    }


    [TestFixture]
    class Whosebug
    {
        [Test]
        public void Hypothetical()
        {
            IUsefulService service = MockRepository.GenerateMock<IUsefulService>();

            try
            {
                var party = new MyParty(service);
            }
            catch(Exception e)
            {
                string[] calls = MagicallyGetTheCallsThatWereMadeToTheMock();
                foreach(var call in calls)
                {
                    //with my visual studio testrunner for nunit 3 I can investigate stored console output
                    Console.WriteLine(call);
                }
                Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
            }
        }

        private string[] MagicallyGetTheCallsThatWereMadeToTheMock()
        {
            return new[]
            {
                "This is where I am lost, I do not know how to get the calls from the repository."
            };
        }
    }
}

我试图在网上找到一些东西,但没有成功。

Rhino Mocks 会记录所有通话吗?我可以访问该列表吗?

编辑:

由于我正在寻找我没有预料到的电话,因此尝试验证预期无效。

我可以使用 GetArgumentsForCallsMadeOn 构建呼叫列表。我可以反映在界面上。我开始使用一种方法,但我目前看不到如何将 MethodInfo 转换为 Action<T>

private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
    Type interfaceType = typeof(Interface);
    List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
    List<string> returnInfos = new List<string>();
    StringBuilder callbuilder = new StringBuilder();

    foreach (var property in interfaceType.GetProperties())
    {
        interfaceMethodInfos.Add(property.GetGetMethod());
        interfaceMethodInfos.Add(property.GetSetMethod());
    }
    foreach (var method in interfaceType.GetMethods())
    {
        interfaceMethodInfos.Add(method);
    }

    foreach (var methodinfo in interfaceMethodInfos)
    {
        Action<Interface> magic = null; //convert methodinfo into action - still missing
        var calls = rhinomock.GetArgumentsForCallsMadeOn(magic); //magic is currently null, here be crash
        foreach (var call in calls)
        {
            bool more = false;
            callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
            foreach (var parameter in call)
            {
                if (more){ callbuilder.Append(", "); }
                if (null == parameter) { callbuilder.Append("<null>"); }
                else { callbuilder.Append(parameter.ToString()); }
                more = true;
            }
            callbuilder.Append(')');
            string callInfo = callbuilder.ToString();
            returnInfos.Add(callInfo);
        }
    }
    return returnInfos;
}

我能够使用反射来获得我想要的输出。 这是测试失败且输出包含所有方法调用的最小示例。

using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Whosebug_namespace
{
    public interface IUsefulService
    {
        object HiddenAmongManyCalls();
        string TestCall2(string arg1, int arg2);
        string FULLACCESS { get; set; }
        string READONLY { get; }
    }

    public class ThirdPartyBase
    {
        private int a = 42;

        public ThirdPartyBase(IUsefulService service)
        {
            service.TestCall2("callA", 1);
            service.TestCall2("callB", 1);
            object liveFastDieYoung = service.HiddenAmongManyCalls();
            service.TestCall2("callA", 2);
            service.TestCall2("callB", 2);
            var a = service.FULLACCESS;
            var b = service.READONLY;
            service.FULLACCESS = "some";
            liveFastDieYoung.Equals(a);
        }
    }

    public class MyParty : ThirdPartyBase
    {
        public MyParty(IUsefulService service) : base(service)
        {

        }
    }


    [TestFixture]
    class Whosebug
    {
        [Test]
        public void Hypothetical()
        {
            IUsefulService service = MockRepository.GenerateMock<IUsefulService>();

            try
            {
                var party = new MyParty(service);
            }
            catch (Exception e)
            {
                var calls = GetCallsList(service);
                foreach (var call in calls)
                {
                    //with my visual studio testrunner for nunit 3 I can investigate stored console output
                    Console.WriteLine(call);
                }
                Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
            }
        }

        private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
        {
            Type interfaceType = typeof(Interface);
            List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
            List<string> returnInfos = new List<string>();
            StringBuilder callbuilder = new StringBuilder();

            foreach (var property in interfaceType.GetProperties())
            {
                AddMethodInfoIfValid(interfaceMethodInfos, property.GetGetMethod());
                AddMethodInfoIfValid(interfaceMethodInfos, property.GetSetMethod());
            }
            foreach (var method in interfaceType.GetMethods())
            {
                AddMethodInfoIfValid(interfaceMethodInfos, method);
            }

            foreach (var methodinfo in interfaceMethodInfos)
            {
                int paramcount = methodinfo.GetParameters().Length;
                object[] args = new object[paramcount];
                Action<Interface> lambdacall = (i) => methodinfo.Invoke(i, args); 
                var calls = rhinomock.GetArgumentsForCallsMadeOn(lambdacall);
                foreach (var call in calls)
                {
                    bool more = false;
                    callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
                    foreach (var parameter in call)
                    {
                        if (more) { callbuilder.Append(", "); }
                        if (null == parameter) { callbuilder.Append("<null>"); }
                        else {
                            callbuilder
                                .Append('(').Append(parameter.GetType().Name).Append(")'")
                                .Append(parameter.ToString()).Append("'");
                        }
                        more = true;
                    }
                    callbuilder.Append(')');
                    string callInfo = callbuilder.ToString();
                    returnInfos.Add(callInfo);
                }
            }
            return returnInfos;
        }

        private static void AddMethodInfoIfValid(List<MethodInfo> interfaceMethodInfos, MethodInfo methodinfo)
        {
            if (null != methodinfo)
            {
                interfaceMethodInfos.Add(methodinfo);
            }
        }
    }
}