gisWeeper
gisWeeper

Reputation: 481

Moq - Call original Method implementation but change one of the input Parameters

I'm using Moq in some Integration testing (updating an existing test script and code that is not my own) and I'm testing a BuinessService that has an email Interface injected into it which sends emails.

public interface IEmailService
{
    void CreateMailItem(string To, string Subject, string Body);
    string GetEmailAddress(string staffmember);
}

Originally I just Moq'd the IEmailService interface and that worked fine but because of the way the code is implemented I need to call the default interface implementation i.e.EmailService to test. I know I shouldn't.

I know I can moq the method like below, but what I want to do is have the code call the original implementation EmailService.CreateMailItem and only change the single parameter so that emails are sent to a test account rather than the real live account.

var emailMock = new Mock<EmailService>() { CallBase = true };
emailMock.Setup(x => x.CreateMailItem("[email protected]", It.IsAny<string>(), It.IsAny<string>()));
email = emailMock.Object;

Can I use Moq to call the original CreateMailItem method but change the 'To' parameter to my test email account and keep the other parameters as they were.?

Upvotes: 1

Views: 5826

Answers (2)

Robin Bennett
Robin Bennett

Reputation: 3231

I think you could mock the function and use a callback to a test function, which changes the address and then calls the real function.

I've not tried it though, it might get stuck in an infinite loop.

emailMock.Setup(x => x.CreateMailItem(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())
    .CallBack<string, string, string>(this.TestCreateMailItem));

email = emailMock.Object;

private void TestCreateMailItem(string to, string from, string address)
{
    emailMock.Object.CreateMailItem("[email protected]", from, address);
}

Upvotes: 2

V0ldek
V0ldek

Reputation: 10563

Whatever it is you're trying to do - you're doing it wrong.

If EmailService is the system you're trying to test, then you should never mock it. Just call the method you want to test with appropriate parameters and Assert the results.

If EmailService is a dependency, then you should never call the actual implementation - that misses the entire point of mocking something, you want to disconnect yourself from the implementation and provide a mocked method that will simply do exactly what is expected of it by the system under test.

EDIT:

You could use Moq and hack this in this way:

var emailInstance = new EmailService():

var emailMock = new Mock<EmailService>() { CallBase = true };

emailMock.Setup(x => x.CreateMailItem(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
    .Callback((_, arg2, arg3) => emailInstance.CreateMailItem("[email protected]", arg2, arg3));

So now when you call your emailMock.CreateMailItem with any arguments, it's gonna redirect the call to the actual instance and exchange the first argument with your test email.

Please note that such a test would be called an integration test. You're actually testing how the modules interact with each other in a live, albeit prefabricated, environment. It would probably be better if you could force the system under test to use the test email rather than use mocks, but this should get the job done.

Upvotes: 5

Related Questions