【问题标题】:should this be mocked or stubbed?这应该被嘲笑或存根吗?
【发布时间】:2012-07-26 09:20:49
【问题描述】:

我有以下方法来测试,我写了两个测试,测试抛出异常的场景,我想知道哪个是正确的。

namespace JimBob.CsvImporter.Entity
{

    public interface IIOManager
    {
        Stream OpenFile(string path);

        TextReader ReturnReader(string path);
    }


    public class IOManager : IIOManager
    {
        public Stream OpenFile(string path)
        {
            return File.Open(path, FileMode.Open);
        }

        public TextReader ReturnReader(string filePath)
        {
            return new StreamReader(filePath);
        }
    }


public class EntityVerification
{

    private IIOManager _iomgr;

    public EntityVerification(IIOManager ioManager)
    {
        this._iomgr = ioManager;
    }

    ...

    /// <summary>
    /// Ensures user can open file.
    /// </summary>
    /// <param name="errorMessageList">A running list of all errors encountered.</param>
    public void ValidateAccessToFile(string filePath, List<string> errorMessageList)
    {
        try
        {
            using (FileStream fs = (FileStream)_iomgr.OpenFile(filePath))
            {
                if (fs.CanRead && fs.CanWrite) { }
                else
                {
                    errorMessageList.Add("Can not read/write to the specified file.");
                }
            }
        }
        catch (Exception e)
        {
            errorMessageList.Add(e.Message);
        }
    }

测试:

    [Test]
    public void ValidateAccessToFile_CanReadWriteToFile_ThrowException()
    {
        List<String> errorMessageList = new List<string>();
        StubService stub = new StubService();
        EntityVerification testObject = new EntityVerification(stub);
        testObject.ValidateAccessToFile("ergesrg", errorMessageList);
        Assert.AreEqual(errorMessageList.Count, 0);
    }

    [Test]
    public void ValidateAccessToFile_CanReadWriteToFile_ThrowsException()
    {
        Mock<IIOManager> mock = new Mock<IIOManager>();
        mock.Setup(x => x.ReturnReader(It.IsAny<string>())).Throws(new InvalidOperation("throw baby."));
        EntityVerification testObject = new EntityVerification(mock.Object);
        List<String> errorMessageList = new List<string>();
        testObject.ValidateAccessToFile("blabla.txt", errorMessageList);
        Assert.AreEqual(errorMessageList.Count, 0);
    }



    public class StubService : IIOManager
    {
        public Exception ex;
        public Stream OpenFile(String path)
        {
            throw ex;
        }
    }

两个测试都只是检查测试的局部变量(在本例中为 errorMessageList)是否包含某些内容,因此我不确定应该使用哪个。

任何 cmets 将不胜感激。

谢谢

【问题讨论】:

  • @SilverNinja,感谢您的编辑。

标签: c# unit-testing c#-4.0 dependency-injection moq


【解决方案1】:

首先,您不应该检查您是否确实将错误消息添加到列表中?

Assert.AreEqual(errorMessageList.Count, 1);

第二,虽然第二个不那么冗长,并且更易读(因为您不需要实现另一个类),没关系 - 这两个测试都是有效的实现相同目标的方法。只需选择一个并继续您的下一个功能...

【讨论】:

  • 不知道为什么我不应该检查它是否添加了一条消息。我没有重新抛出异常,所以我需要检查它在 errorMessageList 中添加的内容,以便我可以确定它是否可以继续到程序的下一个阶段。
  • 是的,所以请检查列表是否包含 one 消息,而不是 zero... 或使用 Assert.That(errorMessageList, Is.Not.Empty);
【解决方案2】:

第二次测试看起来更好。我认为您将使用IIOManager 使用其他方法,您应该维护第一个测试(更新存根),但对第二个测试不做任何事情。

关于IOManagerFileSystem——看起来更合适的类名

【讨论】:

  • "我认为您将使用 IIOManager 使用其他方法,您应该维护第一个测试(更新存根),但对第二个测试不执行任何操作。"对不起,我不明白。请详细说明一下。
  • IIOManager - 是接口,所以你的存根依赖于接口。您必须在 IIOManager 发生任何更改后更新存根(例如添加另一个方法)。模拟(第二次测试)不依赖于接口实现。所以,第二次测试比第一次更容易维护
猜你喜欢
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 2014-05-27
  • 1970-01-01
  • 2020-03-27
相关资源
最近更新 更多