2009-08-14

Stream was not readable

TL;DR - flush & reset, see:

[Fact]
public void BaseStream_Is_Not_Empty()
{
 MemoryStream stream = new MemoryStream();
 LogWriter logWriter = new LogWriter(stream);
 logWriter.WriteLine(new[] { DateTime.Now.ToString("yyyy-MM-dd"), "Log data" });
 logWriter.BaseStream.AutoFlush = true;
 stream.Seek(0, SeekOrigin.Begin);

 using (StreamReader sr = new StreamReader(stream))
 {
  Assert.NotEmpty(sr.ReadToEnd());
 }
}

I recently started writing some tests (in xUnit using Moq + StructureMap) for a service that calls a class -- let's call it LogWriter -- that simply writes formatted logging data to a Stream. After creating an interface for the logging class, ILogWriter, I wanted to write some tests on LogWriter to see if it was working as expected (before testing out my service which depends on ILogWriter).

After the ILogWriter was done, I used StreamReader to check out it's input. The Stream I told it to write to was a MemoryStream (this is unit testing).
 public class LogWriterTests
 {
  [Fact]
  public void BaseStream_Is_Not_Empty()
  {
   MemoryStream stream = new MemoryStream();
   LogWriter logWriter = new LogWriter(stream);
   logWriter.WriteLine(new[] { DateTime.Now.ToString("yyyy-MM-dd"), "Log data" });

   using (StreamReader sr = new StreamReader(stream))
   {
    Assert.NotEmpty(sr.ReadToEnd());
   }
  }
 }


// A basic example
public class LogWriter
{
 public LogWriter(Stream stream)
 {
  BaseStream = new StreamWriter(stream);
 }

 public StreamWriter BaseStream { get; set; }

 public void WriteLine(params object[] logObjects)
 {
  BaseStream.WriteLine(DoSomeFormatting(logObjects));
 }
}

The "BaseStream_Is_Not_Empty" test always failed. The Stream was always empty. Hmmm...how about if we try closing the Stream?
[Fact]
public void BaseStream_Is_Not_Empty()
{
 MemoryStream stream = new MemoryStream();
 LogWriter logWriter = new LogWriter(stream);
 logWriter.WriteLine(new[] { DateTime.Now.ToString("yyyy-MM-dd"), "Log data" });
 logWriter.BaseStream.Close();

 using (StreamReader sr = new StreamReader(stream))
 {
  Assert.NotEmpty(sr.ReadToEnd());
 }
}

Now we would expect to get: Stream was not readable. The Stream has been closed -- you can't read from it. The trick now is to reset the position of the Stream and set the BaseStream of LogWriter to AutoFlush.
[Fact]
public void BaseStream_Is_Not_Empty()
{
 MemoryStream stream = new MemoryStream();
 LogWriter logWriter = new LogWriter(stream);
 logWriter.WriteLine(new[] { DateTime.Now.ToString("yyyy-MM-dd"), "Log data" });
 logWriter.BaseStream.AutoFlush = true;
 stream.Seek(0, SeekOrigin.Begin);

 using (StreamReader sr = new StreamReader(stream))
 {
  Assert.NotEmpty(sr.ReadToEnd());
 }
}

And now our test passes. Moving on...