pixelbadger
pixelbadger

Reputation: 1596

Using Moq, how do I mock a method that changes a stream it takes as a parameter?

I'm trying to test the following method:

public void SaveDashboardToPersistentDashboard(
    Dashboard dashboard, PersistentDashboard persistentDashboard)
{
    using (MemoryStream stream = new MemoryStream())
    {
        dashboard.SaveToXml(stream);
        persistentDashboard.Definition = stream.ToArray();

        persistentDashboard.Name = dashboard.Title.Text;
        _unitOfWork.CommitChanges();
    }
}

The method takes a DevExpress Dashboard, calls SaveToXml (passing in a MemoryStream) and then writes the stream array to a PersistentDashboard POCO's Definition property.

I have no control over the Dashboard class, but would like to mock the SaveToXml method to exclude Dashboard method behaviour from the test. This would involve taking the internal stream and writing an array of known bytes into it.

I'm new to Moq, and can't work out how to change the contents of the stream passed into SaveToXml - at least not without passing the stream into the SaveDashboardToPersistentDashboard method. The stream is incidental to the method's behaviour, so I'm not particularly keen on passing it as a parameter.

Is there any way to achieve what I'm trying to do?

Upvotes: 0

Views: 1359

Answers (1)

bstenzel
bstenzel

Reputation: 1241

This is an issue with your design. Not with the mocking library you use.

Directly accessing frameworks is often a bad idea if you want your code to be testable. That even includes the .NET framework itself. While using DateTime is usually safe, using File can already become a huge pain.

What I'd suggest is to create wrapper classes for the DevExpress classes you use. Then extract interfaces from them which you use in your business logic. You can mock them in your tests no problem then.

Something like that:

public interface IDashboard
{
    void SaveToXml(Stream stream);
}

public class DashboardWrapper : IDashboard
{
    private readonly Dashboard dashboard = new Dashboard();

    public void SaveToXml(Stream stream)
    {
        this.dashboard.SaveToXml(stream);
    }
}

You can use an abstract factory or IoC-Container to create those wrappers.

ETA: Not sure how those Dashboard objects are instantiated. Alternatively, give the wrapper a constructor that takes a Dashboard instance and implement an operator for implicit conversion that uses that constructor.

Upvotes: 3

Related Questions