简体   繁体   English

模拟StreamWriter /确定何时模拟

[英]Mocking a StreamWriter/determining when to mock

I have a class which uses a StreamWriter to write to a file. 我有一个使用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());
    }
}

[Questions] [问题]

1: Is it possible to check that the .Write() method is called? 1:可以检查是否调用了.Write()方法吗?

2: Do i need to wrap a MemoryStream inside the StreamWriter in order to test it, without actually accessing the hard drive. 2:是否需要在不实际访问硬盘驱动器的情况下将MemoryStream包装在StreamWriter内以便对其进行测试。 One of StreamWriters constructors accepts a stream but it states the following + will the UTF-8 encoding affect this? StreamWriters构造函数之一接受一个流,但是它声明以下+ UTF-8编码会对此产生影响吗?

Initializes a new instance of the StreamWriter class for the specified stream by using UTF-8 encoding and the default buffer size. 使用UTF-8编码和默认缓冲区大小为指定的流初始化StreamWriter类的新实例。

3: How do you determine if a class is actually accessing the hd and thus needs to be mocked? 3:如何确定某个班级是否实际上正在访问高清并因此需要模拟? (sorry if this last question sounds stupid, but im genuinely a little puzzled by this.) (对不起,如果最后一个问题听起来很愚蠢,但对此我真的感到有点困惑。)

Have the method write to a TextWriter rather than a StreamWriter. 让该方法写入TextWriter而不是StreamWriter。 Then test the method by passing it a mock TextWriter. 然后通过将其传递给模拟TextWriter来测试该方法。 In the "real" code, of course, you'll pass in a StreamWriter that was created using new StreamWriter(errorLogFilePath, true) . 当然,在“真实”代码中,您将传入使用new StreamWriter(errorLogFilePath, true)创建的new StreamWriter(errorLogFilePath, true)

This yields the following answers to your questions: 这将为您的问题提供以下答案:

  1. Yes
  2. No 没有
  3. You can't generally determine that without decompiling its code. 通常,如果不对代码进行反编译,就无法确定。

A little more detail: 更多细节:

Refactor the method into two methods: 将方法重构为两种方法:

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()); 
}

Test the first method to ensure that it calls the second method with an appropriately-constructed StreamWriter. 测试第一个方法,以确保它使用适当构造的StreamWriter调用第二个方法。 Test the second method to ensure that it calls Write on the passed TextWriter, with appropriate arguments. 测试第二个方法,以确保它使用适当的参数在传递的TextWriter上调用Write Now you've abstracted away the dependency on the hard drive. 现在,您已经抽象了对硬盘驱动器的依赖性。 Your tests don't use the hard drive, but you're testing everything. 您的测试未使用硬盘驱动器,但您正在测试所有内容。

Generally speaking, you could : 一般来说,您可以:

Use a well tested logging library (like NLog, MS Logging Application Block), and spare you developping and maintaining your own. 使用经过良好测试的日志库(例如NLog,MS Logging Application Block),可以避免开发和维护自己的日志库。

Refactor your logging logic (or code calling messageboxes, open file dialogs, and so on) into a service, with its interface. 通过其接口将日志记录逻辑(或调用消息框,打开文件对话框等的代码)重构为服务。 This way you can split your testing strategy : 这样,您可以拆分测试策略:

  • when testing consumers of the loggin service : mock the logging interface to make sure the log method is called. 在测试loggin服务的使用者时:模拟日志记录接口以确保调用log方法。 This will ensure that the logging is correctly called by consumers of your logging service 这将确保您的日志记录服务的使用者正确调用日志记录
  • when testing the logging service implementation, just make sure that expected output matches given input : if you want to write "FOO" to bar.log, effectively call 在测试日志记录服务实现时,只需确保期望的输出与给定的输入相匹配即可:如果要在bar.log中写入“ FOO”,请有效地调用

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

The point is making sure that the component is called, done by mocking. 关键是要确保通过模拟来调用该组件。 Then you can check that the component works as expected. 然后,您可以检查组件是否按预期工作。

I know this is a very old question, but I came across this while trying to solve a similar problem.. namely, how to fake the StreamWriter. 我知道这是一个非常老的问题,但在尝试解决类似问题时遇到了这个问题,即如何伪造StreamWriter。

The way I went about this was by not having the StreamWriter created inside the method as part of the using statement, but created up front, within the ctor (make your class extend from IDisposable and then destroy the StreamWriter in the Dispose method instead). 我解决此问题的方法是,没有在using语句的一部分内在方法内部创建StreamWriter,而是在ctor内预先创建(使您的类从IDisposable扩展,然后在Dispose方法中销毁StreamWriter)。 Then inject a fake over the top of it while under test: 然后在测试过程中在其顶部注入伪造品:

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()
    {

    }
}

My unit test method then looks like this: 我的单元测试方法如下所示:

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