Change value of parameter in NSubstitute

2.1k views Asked by At

I have this method to mock with NSubstitute:

public T VoerStoredProcedureUit<T>(string naam, params SqlParameter[] parameters)

The test method using it sends 2 SqlParameters to this method. VoerStoredProcedureUit is supposed to change the values of these parameters so the tested method can extract that.

I created the following with NSubstitute:

SqlParameter[] param =
    {
        new SqlParameter("@pat_id", SqlDbType.BigInt) {Direction = ParameterDirection.Output, Value = "Melding"},
        new SqlParameter("@Melding", SqlDbType.VarChar, 4096) {Direction = ParameterDirection.Output, Value = 2}
    };
    productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
        Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
        {
            x[1] = param;
            return PatientNieuwResultaat.Succes; 
        });

The setup however rises an exception:

A first chance exception of type 'NSubstitute.Exceptions.ArgumentIsNotOutOrRefException' occurred in NSubstitute.dll

Additional information: Could not set argument 1 (SqlParameter[]) as it is not an out or ref argument.

How do you return a value if the method uses implicitly by reference values?

2

There are 2 answers

0
Willem de Jong On BEST ANSWER

I found a working solution. Assigning a new variable to the parameters did't work somehow, but changing them does. Also, the second of the method parameter is an array, so it should be treated as such.

productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
    Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
    {
        paramPatId = ((SqlParameter[])x[1])[0];
        paramMelding = ((SqlParameter[])x[1])[1];

        paramPatId.Value = (long)2;
        paramMelding.Value = "Melding";

        return PatientNieuwResultaat.Succes; 
    });
1
forsvarir On

If I understand your question correctly, you're trying to return the contents of param when VoerStoredProcedureUit<PatientNieuwResultaat> is called.

In ReturnsForAnyArgs, x[1] refers to the second parameter which is an SqlParameter[]. This isn't a ref/out parameter so you can't reassign it in the caller, which is why you get an error. Instead, you need to copy the elements from your template, into the supplied array. Something like this:

productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
    Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
    {
        for (int i = 0; i < param.Length; i++)
        {
            ((SqlParameter[])x[1])[i] = param[i];
        }
        return PatientNieuwResultaat.Succes;
    });

You could obviously remove the for loop, since you know how many parameters you need to copy...

productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
    Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
    {
        ((SqlParameter[])x[1])[0] = param[0];
        ((SqlParameter[])x[1])[1] = param[1];
        return PatientNieuwResultaat.Succes;
    });