简体   繁体   中英

NSubstitute mock a void method without out/ref parameters

I am trying to mock a void method without 'out' or 'ref' parameters and I am not able to mock it. I want to modify parameter inside the mocked function

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};
});

But when I run this test got the error:

NSubstitute.Exceptions.ArgumentIsNotOutOrRefException: 'Could not set argument 0 (Byte[]) as it is not an out or ref argument.'

Is there any other possibility to change parameter inside void method ?

x[0] refers to the first argument passed to NextBytes , in your case the buffer parameter. As the parameter is not ref or out , changing the array reference within your mocked member won´t have any effect to the calling code. So effectively you're doing this:

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

which of course won't be reflected in the calling code. This is why NSubsitute gives you the exception.

Having said this it's not really clear why you want this, as you're calling code will never reflect whatever your actual implementation of the interface does with that array.

So when your calling code looks like this:

theGenerator.NextBytes(bytes);

that code will still reference the "old" array, not the "new" one (which you try to mock away).

So you will need to provide the param as ref or out to reflect that modification in your calling code.

If you know that your array will allways have four elements you could just modifiy the arrays content , not its 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;
});

So you do not want to match any call to NextBytes , but only those that provide an array with four bytes, making your Arg.Any<byte[]()> effectivly a Arg.Is<byte[]>(x => x.Lengh == 4) .

Thanks to HimBromBeere I catch what I was doing wrong.

So simply I can't pass filled byte array with new, i need to replace each item in array

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;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM