I have the following interfaces
public interface IRibbonCommandsProvider
{
IEnumerable<IRibbonCommand> GetRibbonCommands();
}
public interface IRibbonCommand
{
string Group { get; }
string Tab { get; }
string Name { get; }
string Image { get; }
void Execute();
}
And the follwing substitution code:
public class TabsViewModelTests
{
[Fact]
public void Initialize_BuildsCorrectRibbonTree()
{
var commands = Substitute.For<IRibbonCommandsProvider>();
commands.GetRibbonCommands().Returns(
new[]
{
new RibbonCommand { Tab = "Tab1", Group = "Group1", Name = "Name1" },
new RibbonCommand { Tab = "Tab1", Group = "Group1", Name = "Name2" },
new RibbonCommand { Tab = "Tab2", Group = "Group1", Name = "Name3" },
new RibbonCommand { Tab = "Tab2", Group = "Group2", Name = "Name3" }
});
...
}
private class RibbonCommand : IRibbonCommand
{
public string Group { get; set; }
public string Tab { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public void Execute() {}
}
}
Using NSubstitute, is there a clever way to get rid of the stub RibbonCommand class (that is nothing but a fake IRibbonCommand
implementation - and that's NSubstitute's job) and still have list of fake ribbon commands that is as easily readable as the above?.
I can't come up with a readable way using NSubsitute's .Returns()
fluent method without ending with a lot more (and unreadable) code.
Update: A cool NSubstitute extension method could look like this. I just don't know if and how this can be built:
public static ConfiguredCall ReturnsMany<T>(
this IEnumerable<T> value,
Action<T> configureThis,
params Action<T>[] configureThese)
{
...
}
It would be used like this:
commands.GetRibbonCommands().ReturnsMany(
subst =>
{
subst.Tab.Returns("Tab1");
subst.Group.Returns("Group1");
subst.Name.Returns("Name1");
},
subst =>
{
subst.Tab.Returns("Tab1");
subst.Group.Returns("Group1");
subst.Name.Returns("Name2");
},
subst =>
{
subst.Tab.Returns("Tab2");
subst.Group.Returns("Group1");
subst.Name.Returns("Name3");
},
subst =>
{
subst.Tab.Returns("Tab2");
subst.Group.Returns("Group1");
subst.Name.Returns("Name3");
});
I think what you've got is very good — quite succinct and clear.
If you really want to get rid of the class you can use a substitute creation method for
IRibbonCommand
:This doesn't buy you much, although it does mean your test code will be more protected from changes to the
IRibbonCommand
interface (e.g. an additional property will not require changing your test code), and means you can check received calls and stub other calls on individual items.Aside: Can use argument names if you want to more closely match the original code: