【问题标题】:NSubstitute mock a void method without out/ref parametersNSubstitute 模拟没有输出/引用参数的 void 方法
【发布时间】:2019-03-01 14:23:16
【问题描述】:

我正在尝试模拟没有“out”或“ref”参数的 void 方法,但我无法模拟它。 我想修改模拟函数中的参数

public interface IRandomNumberGenerator
{
    void NextBytes(byte[] buffer);
}

var randomImplementation = Substitute.For<IRandomNumberGenerator>();    
randomImplementation.When(x => x.NextBytes(Arg.Any<byte[]>())).Do(x =>
{
    x[0] = new byte[] {0x4d, 0x65, 0x64, 0x76};
});

但是当我运行这个测试时得到了错误:

NSubstitute.Exceptions.ArgumentIsNotOutOrRefException: '无法设置 参数 0 (Byte[]) 因为它不是 out 或 ref 参数。'

还有没有其他可能改变void方法中的参数?

【问题讨论】:

  • 您似乎想要替换整个数组,这当然需要参数是 ref 或 out。但是,您可以尝试替换数组 elements.
  • 如何将buffer 转换为一个对象(例如,具有bytes 数组属性)并像buffer.bytes = new byte[]{...} here's 一样访问它在C# 中传递对象的工作原理。
  • 您将如何调用该代码?你能分享你打电话给NextBytes的部分吗?
  • @HimBromBeere 我有两个实现,一个是 Random.NextBytes(),第二个是更安全的加密所以调用这样的核心是这样的: var bytesArray = new byte[bytesize]; _randomNumberGenerator.NextBytes(bytesArray);
  • 问题是无论你的生成器实际做什么,除非 bytesArray 没有通过 ref 传递,否则调用 NextBytes 的代码根本无法识别它。

标签: c# nsubstitute


【解决方案1】:

感谢 HimBromBeere 我发现我做错了什么。

所以我不能用新的填充字节数组传递,我需要替换数组中的每个项目

public interface IRandomNumberGenerator
{
    void NextBytes(byte[] buffer);
}

var randomImplementation = Substitute.For<IRandomNumberGenerator>();    
randomImplementation.When(x => x.NextBytes(Arg.Any<byte[]>())).Do(x =>
{
    var byteArray = x.Arg<byte[]>();
    byteArray [0] = 0x4d;
    byteArray [1] = 0x65;
    byteArray [2] = 0x64;
    byteArray [3] = 0x76;
});

【讨论】:

    【解决方案2】:

    x[0] 是指传递给NextBytes 的第一个参数,在您的情况下是buffer 参数。由于参数不是refout,因此更改模拟成员中的数组引用不会对调用代码产生任何影响。你这样做非常有效:

    class TheMoc : IRandomNumberGenerator
    {
        public void NextBytes(byte[] bytes)
        {
            bytes = new byte[] {0x4d, 0x65, 0x64, 0x76};
        }
    }
    

    这当然不会反映在调用代码中。这就是 NSubsitute 为您提供例外的原因。

    话虽如此,您还不清楚为什么要这样做,因为您调用的代码将永远反映您的接口的实际实现对该数组所做的任何事情。

    所以当你的调用代码看起来像这样时:

    theGenerator.NextBytes(bytes);
    

    该代码仍将引用“旧”数组,而不是“新”数组(您试图将其模拟掉)。

    所以您需要将参数提供为refout 以在您的调用代码中反映该修改。

    如果你知道你的数组总是有四个元素,你可以只修改数组content,而不是它的reference

    randomImplementation.When(x => x.NextBytes(Arg.Any<byte[]>())).Do(x =>
    {
        x[0][0] = 0x4d;
        x[0][1] = 0x65;
        x[0][2] = 0x64;
        x[0][3] = 0x76;
    });
    

    所以你不想匹配 anyNextBytes 的调用,而只匹配那些提供四个字节数组的调用,使你的Arg.Any&lt;byte[]()&gt; 有效 成为@ 987654333@.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多