Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subsequent calls to a Mock.Setup result in the same object instance

Tags:

moq

moq-3

I am setting up a Mock as shown below. It is passed into the constructor of the target. The target has a Decrypt method that is called twice within the lifetime of the target. Each time the Decrypt method is called, it Disposes of the certificate that is "newed" up in the Setup. However, when calling the Decrypt object the second time, I am getting an ObjectDisposed method upon attempting the decryption. If I replace this Mock with a Fake implementation of ICertificateHelperAdapter that calls GetCertificate(), then the second call to Decrypt works properly.

I am deducing that when I use the Mock, it is not returning me a new instance of the object on subsequent calls to GetCertificate. Is this by design?

    private Mock<ICertificateHelperAdapter> GetCertificateHelperAdapter()
    {
        Mock<ICertificateHelperAdapter> certificateHelper = new Mock<ICertificateHelperAdapter>();

        certificateHelper.Setup(
            ch => ch.GetCertificate(CertStoreName.My, StoreLocation.LocalMachine, It.IsAny<string>())).Returns(this.GetCertificate()).Verifiable();
        return certificateHelper;
    }

    private X509Certificate2 GetCertificate()
    {
        return new X509Certificate2(Environment.CurrentDirectory + "\\" + "azureconfig.pfx", "dingos");
    }
like image 971
Pete Maroun Avatar asked Feb 24 '12 04:02

Pete Maroun


1 Answers

The different overloads of Returns<T> behaves differently:

The one with T Returns<T>(T value) what you are using is always returning the same instance.

But there is a lazy version which uses Func<T>. They are looks like T Returns<T>(Func<T> value) and they will evaluate each time the parameter function when the setup method is called.

Sample from the Moq site:

// lazy evaluating return value
mock.Setup(foo => foo.GetCount()).Returns(() => count);

Change your setup to:

certificateHelper.Setup(ch => 
   ch.GetCertificate(CertStoreName.My, StoreLocation.LocalMachine, It.IsAny<string>()))
.Returns(() => this.GetCertificate()).Verifiable(); //note the lambda in Returns

And it will call your GetCertificate() twice.

like image 173
nemesv Avatar answered Oct 04 '22 21:10

nemesv