代码之家  ›  专栏  ›  技术社区  ›  gigha

C#mock无法在实际代码中工作

  •  0
  • gigha  · 技术社区  · 9 年前

    我目前有以下方法和代码:

    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的属性,它会给我正确的存根属性:

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

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

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

    提前感谢。

    2 回复  |  直到 9 年前
        1
  •  1
  •   gigha    9 年前

    事实证明,当我将MockSmtpClient类更改为接口时,它是有效的。Moq和Faketieasy显然不支持嘲笑普通班级。

        2
  •  1
  •   Blair Conrad    9 年前

    正如@StevenScott所说,课程可以被嘲笑,但有一些限制。你看到你所描述的行为并不是因为FakeItEay的失败,而是因为你实现和使用的方式 MockSmtpClient .

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

    enter image description here

    因此,当您访问 mockSmtpClient 在编译器 知道 这是一个 模拟SmtpClient ,调用新方法。在测试中,这意味着执行FakeItEay提供的行为。

    然而,生产代码只知道对象是 Smtp客户端 ,以便执行类的(非虚拟)方法。

    为了演示,让我们将FakeItEay从图片中完全删除,只需简单地更改为 模拟SmtpClient :

    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
    

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