簡體   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