.net - 起订量、引用、设置和队列

标签 .net testing moq

我正在测试一个需要“ref”参数的方法。我希望这个参数在每次调用该方法时都返回不同的值(我预计在本次测试中返回 10 次)。我想不出如何 mock 这一点。这是我到目前为止所拥有的 - 无法编译:

var refParentMenuId = It.Is<int>(i => new Queue<int>( new int [] { 1,2,3,4,5,6,7,8,9,10 }).Dequeue);

this.MockMenuRepository.Setup(m => m.Create(It.IsAny<string>, It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), ref refParentMenuId));

我想坚持使用引用而不是返回结构,因为我认为这种方式更直观。

最佳答案

指定 ref 参数的行为是 not supported out of the box ,但是可以添加您自己的扩展方法来支持此行为。有一个解决方案发布here .

对于您的示例,测试看起来有点像这样:

[TestClass]
public class RefUnitTests
{
    private Queue<int> queue = new Queue<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

    [TestMethod]
    public void TestRefArgs()
    {
        int inputInt = 0;

        var repository = new Mock<IRepository>();

        repository
            .Setup(r => r.Create(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), ref inputInt))
            .Returns(0)
            .IgnoreRefMatching()
            .RefCallback<string, int, int, int, int, IRepository>(new MoqExtension.RefAction<string, int, int, int, int>(ReportInfoRefCallBackAction));

        int actualInt = -1;

        for (int i = 1; i <= 10; i++)
        {
            repository.Object.Create(string.Empty, 1, 2, 3, ref actualInt);

            // Assert that we are really dequeuing items
            Assert.AreEqual(i, actualInt);
        }
    }

    public void ReportInfoRefCallBackAction(string a, int b, int c, int d, ref int refInt)
    {
        // You can also assert on the incoming ref value here if you wish, I wrote
        // it to the console so that you can see it is changing.
        Console.WriteLine(refInt);
        refInt = queue.Dequeue();
    }
}

您没有定义要测试的存储库,因此我使用了一个看起来类似的界面:

public interface IRepository
{
    int Create(string arg1, int arg2, int arg3, int arg4, ref int arg);
}

以下是扩展 Moq 所需的代码,改编自上面的链接:

public static class MoqExtension
{
    public delegate void RefAction<TParam1, TParam2, TParam3, TParam4, TRef>(TParam1 param1, TParam2 param2, TParam3 param3, TParam4 param4, ref TRef refVal1);

    public static IReturnsResult<TMock> RefCallback<TParam1, TParam2, TParam3, TParam4, TRef, TMock>(
       this ICallback mock,
       RefAction<TParam1, TParam2, TParam3, TParam4, TRef> action) where TMock : class
    {
        mock.GetType().Assembly
               .GetType("Moq.MethodCall")
               .InvokeMember("SetCallbackWithArguments",
               BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
               null,
               mock,
               new object[] { action });

        return mock as IReturnsResult<TMock>;
    }

    public static ICallback IgnoreRefMatching(this ICallback mock)
    {
        try
        {
            FieldInfo matcherField = typeof(Mock).Assembly.GetType("Moq.MethodCall").GetField("argumentMatchers", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);

            IList argumentMatchers = (IList)matcherField.GetValue(mock);
            Type refMatcherType = typeof(Mock).Assembly.GetType("Moq.Matchers.RefMatcher");
            FieldInfo equalField = refMatcherType.GetField("equals", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);

            foreach (object matcher in argumentMatchers)
            {
                if (matcher.GetType() == refMatcherType)
                    equalField.SetValue(matcher, new Func<object, bool>(delegate(object o) { return true; }));
            }

            return mock;
        }
        catch (NullReferenceException)
        {
            return mock;
        }
    }
}

关于.net - 起订量、引用、设置和队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13304435/

相关文章:

java - Maven/Netbeans 有不同的测试配置文件和环境变量

javascript - 使用 axios 执行经过身份验证的请求时,Jest 返回 "Network Error"

c# - 使用最小起订量的服务模拟异步方法

.net - 为什么在创建 X509Certificate2 对象时会收到拒绝访问错误?

.net - IEnumerator<T> 实现

c# - Entity Framework 数据库优先,同表名和列名映射

c# - 滥用最小起订量来测试 if 条件

c# - 关注 ListView 最后添加的项目

forms - 如何在测试 Angular 2 react 形式时使用 setValue 和 patchValue

c# 模拟接口(interface) vs 模拟类