0

我有一个使用 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:我是否需要在 StreamWriter 中包装 MemoryStream 以对其进行测试,而无需实际访问硬盘驱动器。StreamWriters 构造函数之一接受流,但它指出以下 + UTF-8 编码会影响这一点吗?

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

3:你如何确定一个类是否真的在访问 hd 并因此需要被模拟?(对不起,如果最后一个问题听起来很愚蠢,但我真的对此有点困惑。)

4

3 回答 3

3

让方法写入 TextWriter 而不是 StreamWriter。然后通过传递一个模拟 TextWriter 来测试该方法。当然,在“真实”代码中,您将传入一个使用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 调用第二个方法。测试第二种方法以确保它Write使用适当的参数调用传递的 TextWriter。现在您已经抽象出对硬盘驱动器的依赖。您的测试不使用硬盘驱动器,但您正在测试所有内容。

于 2012-09-11T09:40:33.980 回答
1

一般来说,您可以:

使用经过良好测试的日志库(如 NLog、MS 日志应用程序块),让您无需开发和维护自己的日志库。

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

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

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

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

于 2012-09-11T09:51:18.557 回答
0

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

我解决这个问题的方法是不将 StreamWriter 作为 using 语句的一部分在方法内创建,而是在 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");
} 
于 2018-06-13T15:47:57.400 回答