Ken Pespisa
Ken Pespisa

Reputation: 22264

Options for unit testing a return type I can't easily create

I need to unit test a method that returns a type I can't easily fake or instantiate. The type implements IQueryable<T> which I originally thought I could use to my advantage, but I don't see how at this point.

For example:

public sealed class MyTrickyClass<T> : IQueryable<T>
{
    ...
}

public MyTrickyClass<T> GetData()
{
    return repository.GetAllData();
}

and my unit test

[Test Method]
public void CanGetData()
{
    var data = (new List<Record>() { new Record() }).AsQueryable();
    var mockRepository = new Mock<IRepository<Record>>();
    mockRepository.Setup(s => s.GetAllData()).Returns(data);

    MyService service = new MyService(mockRepository.Object);
    var result = service.GetData();

    Assert.IsNotNull(result);

}

This won't compile because the return type of GetAllData() is MyTrickyClass<T>. If I try to cast data to a MyTrickyClass<Record> type, the cast fails.

All this makes sense, but it leaves me wondering what the right solution is. What are some workarounds for this kind of situation? I may be able to change the MyTrickyClass, but ideally I'd like to find a solution that leaves it alone.

Upvotes: 2

Views: 646

Answers (2)

Lunivore
Lunivore

Reputation: 17657

Your data variable in the test is an IQueryable<Record>, not a MyTrickyClass<Record>.

Here are some possibilities for fixing it:

  • Change data in the test to be a MyTrickyClass<Record> (though I'm guessing if this was possible you'd already have done it)
  • Make MyTrickyClass easier to construct, then do the above
  • Change the interface of IRepository so that it returns an IQueryable instead of a MyTrickyClass (which is best if all it needs is the IQueryable anyway)
  • Wrap the repository in a layer which lets you also wrap the return value. It's another layer of abstraction, but if you find you can't change the repository or MyTrickyClass then you probably want to be isolating yourself from it anyway
  • As @Erik Dietrich suggested, you could make MyTrickyClass implement an interface. However, you still won't be able to create data using an IQueryable as the cast will fail. You could create a mock of ITrickyClass instead, though, or create a little stub class that implements the interface (if MyTrickyClass is a domain object, you'll probably be using it in a lot of places anyway, so a hand-coded stub may be more useful).

Upvotes: 2

Erik Dietrich
Erik Dietrich

Reputation: 6090

You could have MyTrickyClass<T> implement interface ITrickyClass<T>, which inherits from IQueryable<T>. That seems minimally invasive to your class itself, and you'd have a good seam for mocking.

Upvotes: 2

Related Questions