【问题标题】:C# mock not working in actual codeC# 模拟在实际代码中不起作用
【发布时间】:2015-03-26 12:39:25
【问题描述】:

我目前有以下带代码的方法:

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

使用以下测试代码调用它:

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

当我在实际代码中调用模拟对象的主机和端口时,它给了我\

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

但是,如果我从测试代码中调用模拟的属性,它会给我正确的存根属性:

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

如您所见,在实际代码中它没有返回主机和默认端口,而在测试代码中它为我提供了来自模拟框架的正确存根属性,而对象在两种环境中都是相同的。

当我使用模拟框架 Moq 而不是 FakeItEasy(如示例中所示)时,情况完全相同。

提前致谢。

【问题讨论】:

    标签: c# unit-testing mocking fakeiteasy moq-3


    【解决方案1】:

    事实证明,当我将 MockSmtpClient 类更改为接口时,它起作用了。 Moq 和 Fakeiteasy 显然不支持模拟普通类。

    【讨论】:

    • 很高兴您有一个可行的解决方案。项目维基解释what FakeItEasy allows you to fake
    • 正如 Wiki 所指出的,可以模拟类,只是有一些限制。我使用 FakeItEasy 在我的测试中模拟课程没有问题。
    【解决方案2】:

    正如@StevenScott 所说,可以模拟类,但有一些限制。您看到您描述的行为不是因为 FakeItEasy 中的失败,而是因为您实现和使用 MockSmtpClient 的方式。

    HostPort 属性隐藏了 SmtpClient 中的相同属性。您可以在下面的警告中看到这一点:

    因此,当您在编译器知道它是MockSmtpClient 的情况下访问mockSmtpClient 时,就会调用新方法。在您的测试中,这意味着执行了 FakeItEasy 提供的行为。

    但是,生产代码只知道对象为SmtpClient,因此会执行该类的(非虚拟)方法。

    为了演示,让我们把 FakeItEasy 完全去掉,简单地更改为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; }
        }
    }
    

    还有这个测试:

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

    这会产生这个输出:

    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
    

    这类似于您使用 FakeItEasy 创建 mockSmtpClient 时的行为。

    【讨论】:

      猜你喜欢
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      相关资源
      最近更新 更多