繁体   English   中英

模拟StreamWriter /确定何时模拟

[英]Mocking a StreamWriter/determining when to mock

我有一个使用StreamWriter写入文件的类。

public void CreateLog(string errorLogFilePath, StringBuilder errorLogBuilder, string errorMessage)
{
    using (StreamWriter sw = new StreamWriter(errorLogFilePath, true)
    {
        errorLogBuilder.Apend("An error was discovered.");
        //....
        sw.Write(errorLogBuilder.ToString());
    }
}

[问题]

1:可以检查是否调用了.Write()方法吗?

2:是否需要在不实际访问硬盘驱动器的情况下将MemoryStream包装在StreamWriter内以便对其进行测试。 StreamWriters构造函数之一接受一个流,但是它声明以下+ UTF-8编码会对此产生影响吗?

使用UTF-8编码和默认缓冲区大小为指定的流初始化StreamWriter类的新实例。

3:如何确定某个班级是否实际上正在访问高清并因此需要模拟? (对不起,如果最后一个问题听起来很愚蠢,但对此我真的感到有点困惑。)

让该方法写入TextWriter而不是StreamWriter。 然后通过将其传递给模拟TextWriter来测试该方法。 当然,在“真实”代码中,您将传入使用new StreamWriter(errorLogFilePath, true)创建的new StreamWriter(errorLogFilePath, true)

这将为您的问题提供以下答案:

  1. 没有
  2. 通常,如果不对代码进行反编译,就无法确定。

更多细节:

将方法重构为两种方法:

public void CreateLog(string errorLogFilePath, StringBuilder errorLogBuilder, string errorMessage) 
{ 
    using (StreamWriter sw = new StreamWriter(errorLogFilePath, true) 
    {
        CreateLog(sw, errorLogBuilder, errorMessage); 
    } 
} 

public void CreateLog(TextWriter writer, StringBuilder errorLogBuilder, string errorMessage)
{
    errorLogBuilder.Apend("An error was discovered."); 
    //.... 
    writer.Write(errorLogBuilder.ToString()); 
}

测试第一个方法,以确保它使用适当构造的StreamWriter调用第二个方法。 测试第二个方法,以确保它使用适当的参数在传递的TextWriter上调用Write 现在,您已经抽象了对硬盘驱动器的依赖性。 您的测试未使用硬盘驱动器,但您正在测试所有内容。

一般来说,您可以:

使用经过良好测试的日志库(例如NLog,MS Logging Application Block),可以避免开发和维护自己的日志库。

通过其接口将日志记录逻辑(或调用消息框,打开文件对话框等的代码)重构为服务。 这样,您可以拆分测试策略:

  • 在测试loggin服务的使用者时:模拟日志记录接口以确保调用log方法。 这将确保您的日志记录服务的使用者正确调用日志记录
  • 在测试日志记录服务实现时,只需确保期望的输出与给定的输入相匹配即可:如果要在bar.log中写入“ FOO”,请有效地调用

IE浏览器:

// arrrange
File.Delete("bar.log")

// act
CreateLog("bar.log", errorLogBuilder, "FOO")

// assert
Assert.IsTrue( File.Exists("bar.log") )
Assert.IsTrue( File.ReadAllLines("bar.log").First() == "FOO")

关键是要确保通过模拟来调用该组件。 然后,您可以检查组件是否按预期工作。

我知道这是一个非常老的问题,但在尝试解决类似问题时遇到了这个问题,即如何伪造StreamWriter。

我解决此问题的方法是,没有在using语句的一部分内在方法内部创建StreamWriter,而是在ctor内预先创建(使您的类从IDisposable扩展,然后在Dispose方法中销毁StreamWriter)。 然后在测试过程中在其顶部注入伪造品:

internal class FakeStreamWriter : StreamWriter
{
    public List<string> Writes { get; set; } = new List<string>();

    public FakeStreamWriter() : base(new MemoryStream()) { }

    public override void Write(string value)
    {
        WriteLine(value);
    }
    public override void WriteLine(string value)
    {
        Writes.Add(value);
    }

    public override void Flush()
    {

    }
}

我的单元测试方法如下所示:

public void SmtpStream_Negotiate_EhloResultsCorrectly()
{
    var ctx = new APIContext();
    var logger = new FakeLogger();
    var writer = new FakeStreamWriter();
    var reader = new FakeStreamReader { Line = "EHLO test.com" };
    var stream = new SmtpStream(logger, ctx, new MemoryStream())
    {
        _writer = writer,
        _reader = reader
    };

    Exception ex = null;

    try
    {
        stream.Negotiate(ctx);
    }
    catch (Exception x)
    {
        ex = x;
    }

    Assert.IsNull(ex);
    Assert.IsTrue(writer.Writes.ElementAt(0) == "250 Hello test.com");
    Assert.IsTrue(writer.Writes.ElementAt(1) == "250 STARTTLS");
} 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM