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

4

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

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

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

namespace StackOverflow_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 StackOverflow
    {
        [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;
}

是的,Rhinomocks记录所有方法调用。您可以使用AssertWasCalled验证它们的执行。 - Old Fox
@OldFox 我可以验证我期望的一切,但是像上面那样调用时发生了我不期望的事情,我想创建一个报告来显示发生了什么。我认为 VerifyAllExpectations 对我没有帮助。 - Johannes
2
在单元测试中,你需要验证预期的行为。监听所有调用是一种不好的做法。VerifyAllExpectations并不能解决你的问题。当你不希望允许出现意外调用时,你需要使用严格模拟(目前使用这种模拟被视为一种不好的做法...)。如果你仍然想要访问记录:可以使用反射或下载Rhinomocks源代码并进行一些修改... - Old Fox
1个回答

2

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

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

namespace StackOverflow_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 StackOverflow
    {
        [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);
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接