MemoryStream jako zamiennik dla wyjścia konsoli (lub pliku)

Obecnie tworze aplikację konsolową, jest to REPL dla mojego tyci-mini języka (język nie istnieje poza REPL).

Postanowiłem, że istniejącą funkcję print pokryję testami jednostkowymi. Zastanawiałem się jak to zrobić. Problem polegał na tym że wynik przekazywałem na ekran i teraz miałem zagwozdkę jak ten tekst przechwycić.
Dowiedziałem się o klasie MemoryStream, który tworzy strumień piszący po pamięci przydzielonej dla klasy.
Moją klasę PrintMethod, musiałem zmodyfikować z:

public override Result Run()
{
    string text = base.paramList["text"].Value;
    text = getVariablesFromMemory(text);
    Console.WriteLine(text);
    return new PrintResult(text);
}

na:

TextWriter output;
public PrintMethod(string textToPrint,TextWriter output)
    : base("Print")
{
    base.loadParametr("text", new Parametr(textToPrint));
    this.output = output;
}
  
public override Result Run()
{
    string text = base.paramList["text"].Value;
    text = getVariablesFromMemory(text);
    output.WriteLine(text);
    return new PrintResult(text);
}

Teraz ta klasa mogła przyjąć dowolny obiekt typu TextWriter (który jest typem abstrakcyjnym). Wykorzystałem StreamWriter (który jest typem dziedziczonym po TextWriter). Jeden z konstruktorów StreamWriter przyjmuje klasę Stream poszedłem typ tropem i utworzyłem obiekty w następujący sposób:

using (var memoryStream = new MemoryStream())
{
    TextWriter memoryWriter = new StreamWriter(memoryStream);

    PrintMethod printMethod = new PrintMethod(text, memoryWriter);
    printMethod.Run();
    memoryWriter.Flush();
    //...
}

Teraz tylko potrzebowałem sposobu na odczyt tekstu który został zapisany do MemoryStream. Pomyślałem że odczyt jest podobny jak zapis, więc utworzyłem obiekt StreamReader i wykonałem funkcję ReadLine():

string output;
using (var memoryStream = new MemoryStream())
{
//..
TextReader memoryReader = new StreamReader(memoryStream);
output = memoryReader.ReadLine();
}

Jednak za każdym razem string zwracany przez ReadLine() był pusty! Musiałem się użyć Google i dzięki StackOverflow.com otrzymałem odpowiedź.

Zapomniałem przesunąć wskaźnik będący w klasie MemoryStream, w taki sposób

memoryStream.Position = 0;

I dzięki takim zabiegom mogłem się cieszyć działającymi testami jednostkowymi.

Podsumowanie, jeden test jednostkowy (wykorzystuje bibliotekę do testów NUnit):

private static string printTextToMemory(string text)
{
    string output;
    using (var memoryStream = new MemoryStream())
    {
        TextWriter memoryWriter = new StreamWriter(memoryStream);

        PrintMethod printMethod = new PrintMethod(text, memoryWriter);
        printMethod.Run();
        memoryWriter.Flush();
        memoryStream.Position = 0;
        TextReader memoryReader = new StreamReader(memoryStream);

        output = memoryReader.ReadLine();
    }
    return output;
}
[Test]
public void WriteSimpleText()
{
    string output;
    output = printTextToMemory("Simple Text");
    Assert.AreEqual("Simple Text", output);
}

Podziękowania dla Jerzy Goworski za ciągłe poprawianie moich wypocin.