Executing callbacks

341 views
Skip to first unread message

David Burela

unread,
Oct 3, 2010, 8:48:29 PM10/3/10
to NSubstitute
my Silverlight application architecture looks like this

BusinessLogic
Repository
DomainDataContext

Because of this everything happens asynchronously.

My business logic pulls data from the repositories, but again because
it is Async, I need to wait for a callback before I can do anything
with the data.

e.g.

interface IDataRepository
{
void GetMyData(Action<MyData> callback);
}

List<Entities> myList = new List<Entities>();
PopulateDropdownList()
{
IDataRepository repo = new DataRepository();
repo.GetMyData(callback =>
{
foreach(var item in callback.enities)
myList.Add(item);
});
}


I now want to unit test test the PopulateDropdownList() method to
check that when i get 5 items back from the repository, that the code
did update myList to have 5 items.

Doing it this way http://gist.github.com/604153 does not work, as that
implies I have access to the callbac, which I wouldn't in this case.

Here is an example of how I'm trying to do the unit test
[TestMethod]
public void MyListShouldHave5Items()
{
// Arrange
var data = new List<MyData>{ new MyDa.....

var dataRepository = Substitute.For<IDataRepository>();
// need some code here to invoke the callback with the data
//dataRepository.WhenForAnyArgs(x =>
x.GetMyData()).Do( x(data)??
var viewModel = new ViewModel(dataRepository);


// Act
viewModel.PopulateDropdownList();

// Assert
Assert.AreEqual(5, viewModel.MyList.Count);
}

David Tchepak

unread,
Oct 4, 2010, 10:05:47 PM10/4/10
to nsubs...@googlegroups.com
Hi David,

This works for me:

[Test]
public void MyListShouldHave5Items()
{
    var data = new MyData(Enumerable.Range(1, 5).Select(x => new Entities())); /* Not sure exactly on the api here, so this is a guess */
    var dataRepository = Substitute.For<IDataRepository>();
    dataRepository
        .WhenForAnyArgs(x => x.GetMyData(null))
        .Do(x =>
            {
                var callback = x.Arg<Action<MyData>>();
                callback(data);
            });
    var viewModel = new ViewModel(dataRepository);

    viewModel.PopulateDropdownList();

    Assert.AreEqual(5, viewModel.MyList.Count);
}

The "var callback = x.Arg<Action<MyData>>();" line picks the first argument that is of type Action<MyData>, although it may be clearer to just write "var callback = (Action<MyData>) x[0];" (first arg, cast as Action<MyData>).

Another approach you can take is to encapsulate this in a Command (which can work nicely with MVVM), so your ViewModel looks synchronous and is a bit easier to test. You'll still need to test the callback eventually, but may be able to do this by just checking the method it passes it or integration test it.

Hope this helps.

Regards,
David



--
You received this message because you are subscribed to the Google Groups "NSubstitute" group.
To post to this group, send email to nsubs...@googlegroups.com.
To unsubscribe from this group, send email to nsubstitute...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nsubstitute?hl=en.


David Burela

unread,
Oct 4, 2010, 10:56:52 PM10/4/10
to nsubs...@googlegroups.com
That worked perfectly.
The last bit I was missing was
var callback = x.Arg<Action<MyData>>();
So that is what you meant on twitter by "You can parse the input to get a reference to the callback"

and FYI
var data = new List<MyData> { item1, item2..{
worked fine

Thanks a lot for getting back to me.
Reply all
Reply to author
Forward
0 new messages