Re: [nsubstitute] Substitution of partial interfaces

202 views
Skip to first unread message

David Tchepak

unread,
Mar 13, 2013, 4:54:09 PM3/13/13
to nsubs...@googlegroups.com
Hi David, 

So you'd like to use a concrete implementation for ICollection<int>, but keep the rest of IMyDetails / IMyBase going through the normal substitution logic?




On Wed, Mar 13, 2013 at 11:29 PM, David Wyles <dcw...@gmail.com> wrote:
I have checked in this group, but the post "Does NSubstitute have the ability to mock using class inheritance?" does not answer the question or the question I am about to ask.

Consider:

interface IMyName
{
    string Name { get; set; }
}

interface IMyDetails : ICollection<int>, IMyBase
{
    string Details { get; set; }
}

I'm going to create a substitute for IMyDetails, but don't which to substitute the entire interface for ICollection<int>.

public void Test()
{
    IMyDetails sub = Substitute.For<IMyDetails>();
    sub.Name = "David";
    sub.Details = Wyles;

    // and now I want to substitute the ICollection<int> intergace entirely.
    List<int> subList = new subList();
    List.Add(1);
    List.Add(2);
    // I'd like to do this 
    sub.Implements<ICollection<int>>.With( subList );
    // or something like this
    sub.AsCastable<ICollection<int>>.Returns( subList );

    Assert.IsTrue( sub.Contains( 2 ) );
    Assert.IsEqual( 2, sub.Count );
}

The Implements or AsCastable as just ideas for names, if something already exists to do this, or if anyone thinks this is of value or just not worth while then please comment.

This is a hypothetical example, I have a much more complex use case with a much bigger interface but wish to reuse a stub already created. 

Thanks,

David.

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

David Wyles

unread,
Mar 13, 2013, 5:39:02 PM3/13/13
to nsubs...@googlegroups.com
Yes, that's what I would like. I don't see the point in stubbing a complete collection as I already have one I can use, which doesn't need testing - List in this case.

Thanks,

David.

David Tchepak

unread,
Mar 13, 2013, 6:35:10 PM3/13/13
to nsubs...@googlegroups.com
NSub can't do this.

Ideally I'd try and split the responsibilities of this dependency (could even pass the same object as two dependencies into the SUT, once as IDetails and once as ICollection?). 

If that's not going to work for you, you could try a custom class to wrap what you're testing. Make non-virtual, concrete members that will be ignored by NSub, and then keep the members you want to substitute virtual or abstract. A little bit more work but I think it makes what's happening fairly clear:

    public class TestMyDetails : IMyDetails
    {
        //Concrete list. Non-virtual.
        public List<int> BackingList;
        public IEnumerator<int> GetEnumerator() { return BackingList.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
        public void Add(int item) { BackingList.Add(item); }
        public void Clear() { BackingList.Clear(); }
        public bool Contains(int item) { return BackingList.Contains(item); }
        public void CopyTo(int[] array, int arrayIndex) { BackingList.CopyTo(array, arrayIndex); }
        public bool Remove(int item) { return BackingList.Remove(item); } 
        public int Count { get { return BackingList.Count; } }
        public bool IsReadOnly { get { return false; } }

        //Members to sub. Must be virtual or abstract to be intercepted by NSub
        public virtual string Name { get; set; }
        public virtual string Details { get; set; }
    }

    [Test]
    public void Example()
    {
        var details = Substitute.For<TestMyDetails>();
        details.BackingList = new List<int> {1, 2, 3, 4};
        details.Name.Returns("foo");

        details.Name.ShouldBe("foo");
        details.Count.ShouldBe(4);
    }

Messy, but the best I can come up with at the moment.

Regards,
David

David Wyles

unread,
Mar 18, 2013, 5:28:16 AM3/18/13
to nsubs...@googlegroups.com
Thanks, in the end I refactored my class and its use to allow me to substitute something for an IQueryable interface. Basically I use aggregation instead of inheritance, and supplied an AsQueryable method.

David.
Reply all
Reply to author
Forward
0 new messages