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

用MOQ模拟同一接口中的方法

  •  4
  • Gerard  · 技术社区  · 14 年前

    我在服务中有一个方法要测试。该方法调用同一类中的另一个方法。这个方法已经测试过了,所以我想模拟这个方法。

    这是我的设置:

    private readonly Mock<INewsLetterRepository> _mockNewsLetterRepository;
    private readonly Mock<INewsLetterService> _mockNewsLetterService;
    private readonly INewsLetterService _newsLetterService;
    
    public NewsLetterServiceTest()
    {
        _mockNewsLetterRepository = new Mock<INewsLetterRepository>();
        _mockNewsLetterService = new Mock<INewsLetterService> {CallBase = true};
        _newsLetterService = new NewsLetterService(_mockNewsLetterRepository.Object);
    }
    

    这是我正在使用的测试:

    [TestMethod]
    public void CreateNewsLetter_Should_Return_Empty_NewsLetter()
    {
        var template = new Template
                       {
                           PlaceHolders = new List<TemplatePlaceholder>()
                       };
        var newsLetter = new NewsLetter {Template = template};
        const string content = "<html><body><!--BROWSER--></body></html>";
        _mockNewsLetterService.Setup(x => x.BuildNewsLetterHTML(It.IsAny<NewsLetter>())).Returns(content);
    
        var actual = _mockNewsLetterService.Object.CreateNewsLetter(newsLetter);
        Assert.AreEqual(content, actual);
    }
    

    现在的问题是我正在模拟的函数:BuildNewsLetterHTML返回null,而不是它应该返回的内容。

    下面是我要测试的函数的简化版本:

    public string CreateNewsLetter(NewsLetter newsLetter)
    {
        var newsletterHTML = BuildNewsLetterHTML(newsLetter);
        return newsletterHTML;
    }
    

    所以问题是,至少在我看来,我模拟的函数没有返回它应该返回的内容字符串。测试失败 Assert.AreEqual 因为实际值为空。你们中有人知道为什么实际是空的吗?

    提前谢谢。

    1 回复  |  直到 14 年前
        1
  •  6
  •   CRice    14 年前

    看来问题是你在打电话 Mock<T>'s CreateNewsLetter方法,该方法尚未设置,而且似乎也是您正在测试的方法。你不应该对你的假货进行测试,他们应该替换掉生产代码来帮助测试其他代码。

    我建议你用 extract and override pattern 在这种情况下,因为您希望在具有正在测试的方法的同一类的方法中导致伪实现。

    Moq在某些情况下是很好的,但是我不认为在情况需要时使用一个小的可读存根有什么问题。

    public class YourTestClass
    {
        [TestMethod]
        public void CreateNewsLetter_Should_Return_Empty_NewsLetter()
        {
            var template = new Template
            {
                PlaceHolders = new List<TemplatePlaceholder>()
            };
            var newsLetter = new NewsLetter { Template = template };
    
            const string content = "<html><body><!--BROWSER--></body></html>";
    
            INewsletterService service = new BuildNewsLetterStub(content);
            string actual = service.CreateNewsLetter(newsLetter);
    
            Assert.AreEqual(content, actual);
        }
    }
    
    
    public class BuildNewsLetterStub : NewsLetterService
    {
        private string _letter;
    
        public BuildNewsLetterStub(string letter)
        {
            _letter = letter;
        }
        public override string BuildNewsLetterHTML(NewsLetter newsLetter)
        {
            return _letter;
        }
    }
    

    若要重写BuildNewsLetterHTML,必须将其标记为虚拟。