Search code examples
moqmoq-3

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


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

Solution

  • 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.