0

I currently have the following method with code:

public bool SendMail(ref MailData data)
    SmtpClient smtpClient = this.smtpClient;
    Console.WriteLine("SMTP CLIENT: " + smtpClient.ToString());
    Console.WriteLine("SMTP PORT: " + smtpClient.Port);
    Console.WriteLine("SMTP HOST: " + smtpClient.Host);
}

With the following testcode calling it:

 public class MockSmtpClient : SmtpClient {
    public virtual void Send(MailMessage mailMessage) {
    }
    public virtual string Host
    {
        get
        {
            return Host;
        }
    }
    public virtual int Port
    {
        get
        {
           return Port;
        }
    }
 }

 ... (actual testcode:) ...


 MailData mailData = new MailData {
   HostAddress = "mydomain.com",
 };

 var mockSmtpClient = A.Fake<MockSmtpClient>();
 var mailerMock = new Mailer();

 // Setup
 It.IsAny<SmtpDeliveryMethod>())).Returns(mockSmtpClient.Object);
 A.CallTo(() => mockSmtpClient.Host).Returns(mailData.HostAddress);
 A.CallTo(() => mockSmtpClient.Port).Returns(22);

 // Act
 mailerMock.smtpClient = mockSmtpClient;
 mailerMock.SendMail(ref mailData);
 Console.WriteLine("MOCK SMTP CLIENT FROM TEST: " + mockSmtpClient);
 Console.WriteLine("SMTP HOST FROM UT: " + mockSmtpClient.Host);
 Console.WriteLine("SMTP PORT FROM UT: " + mockSmtpClient.Port);

When I call the mock object's host and port in the actual code it is giving me \

SMTP CLIENT: Faked ServiCommTests.MockSmtpClient
SMTP PORT: 25
SMTP HOST: 

However, if I call the mock's properties from the test code it's giving me the correct stubbed properties:

MOCK SMTP CLIENT FROM TEST: Faked ServiCommTests.MockSmtpClient
SMTP HOST FROM UT: mydomain.com
SMTP PORT FROM UT: 22

As you can see, in the actual code it is returning no host and default port while in the testcode it is giving me the correct stubbed properties from the mocking framework, while the object is the same in both environments.

It goes exactly the same when I use the mocking framework Moq instead of FakeItEasy (as in the example).

Thanks in advance.

gigha
  • 41
  • 1
  • 10

2 Answers2

1

It turned out that it worked when I changed my MockSmtpClient class to an interface. Moq and Fakeiteasy apparantly don't support mocking normal classes.

gigha
  • 41
  • 1
  • 10
  • I'm glad you have a working solution. The project wiki explains [what FakeItEasy allows you to fake](https://github.com/FakeItEasy/FakeItEasy/wiki/What-can-be-faked). – Blair Conrad Mar 26 '15 at 14:23
  • 1
    As the Wiki indicates, classes can be mocked, there are just some restrictions. I mock classes in my tests with FakeItEasy without a problem. – Steven Scott Mar 26 '15 at 16:00
1

As @StevenScott says, classes can be mocked, with some restrictions. You see the behaviour that you described not because of a failing in FakeItEasy, but because of the way you've implemented and used MockSmtpClient.

The Host and Port properties hide the same properties in SmtpClient. You can see this in the warning below:

enter image description here

So when you access mockSmtpClient in a situation where the compiler knows that it's a MockSmtpClient, the new methods are called. In your test, this means that the FakeItEasy-supplied behaviour executes.

However, the production code only knows of the object as a SmtpClient, so that class's (non-virtual) method is executed.

To demonstrate, let's take FakeItEasy out of the picture altogether, with a simple change to MockSmtpClient:

public class MockSmtpClient : SmtpClient
{
    public virtual void Send(MailMessage mailMessage)
    {
    }

    public virtual string Host
    {
        get { return "mocksmtpclient.local"; }
    }

    public virtual int Port
    {
        get { return 17; }
    }
}

and this test:

[Test]
public void Test2()
{
    MailData mailData = new MailData
    {
        HostAddress = "mydomain.com",
    };

    var mockSmtpClient = new MockSmtpClient();
    var mailerMock = new Mailer();

    // Act
    mailerMock.smtpClient = mockSmtpClient;
    mailerMock.SendMail(ref mailData);
    Console.WriteLine("SMTP CLIENT FROM TEST: " + mockSmtpClient);
    Console.WriteLine("SMTP HOST FROM TEST: " + mockSmtpClient.Host);
    Console.WriteLine("SMTP PORT FROM TEST: " + mockSmtpClient.Port);
}

This produces this output:

SMTP CLIENT: GighaQuestion.MockSmtpClient
SMTP HOST: 
SMTP PORT: 25
SMTP CLIENT FROM TEST: GighaQuestion.MockSmtpClient
SMTP HOST FROM TEST: mocksmtpclient.local
SMTP PORT FROM TEST: 17

Which is analogous to the behaviour you had when creating mockSmtpClient using FakeItEasy.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111