I'm reading a lot of documentation and examples about how to properly unit test things combining the three components in the title. I came up with a test method for a method on my business logic, but it feels very clunky and dirty.
I'd like to get some feedback from people more experienced on this topic to see how I can improve it.
Here's the code, explanation follows:
[Fact]
public void ShouldGetItemWithSameId()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var facade = fixture.Freeze<Mock<IDataFacade>>();
facade.Setup(c => c.Get(It.IsAny<int>())).Returns((int i) => new Item { Key = i });
var sut = fixture.Create<BusinessLogic>();
var expected = fixture.Create<int>();
Assert.Equal(expected, sut.Get(expected).Key);
}
My BusinessLogic
class takes an IDataFacade
as constructor parameter, which is responsible in its Get(int)
method to retrieve the item with the same Id, pretty basic stuff.
I freeze the IDataFacade
mock and I set it up to construct an object matching the Id in It.IsAny<int>
. I then create my SUT and test it. Works fine.
I'd like to understand if I can improve things considering the following:
Query
method that takes a class containing a lot of properties that will be used as filters on matching properties on the type being queried. In this case I wouldn't know how to properly do the "Setup" part of the mock, since I have to initialize all, or close to all, the properties of the returned type, and in this scenario it's not a single Item but a whole collectionI have some other tests using Theory
with AutoMoqData
but I was unable to achieve this test (and I think the more complex ones) using that approach, so I switched back to plain Fact
with manually instantiated fixture.
Any help will be extremely appreciated.
Overall, the original test looks good. It's not possible nor easy to extract the setup of Stubs and Mocks out of the test, in a generic fashion.
What you can do though, is minimize the Arrange phase of the test. Here's the original test re-written using AutoFixture.Xunit's own unit-testing DSL:
[Theory, TestConventions]
public void ShouldGetItemWithSameId(
[Frozen]Mock<IDataFacade> facadeStub,
BusinessLogic sut,
int expected)
{
facadeStub
.Setup(c => c.Get(It.IsAny<int>()))
.Returns((int i) => new Item { Key = i });
var result = sut.Get(expected);
var actual = result.Key;
Assert.Equal(expected, actual);
}
The TestConventions
attribute is defined as:
public class TestConventionsAttribute : AutoDataAttribute
{
public TestConventionsAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
HTH
Sample types used in the example:
public class Item
{
public int Key { get; set; }
}
public interface IDataFacade
{
Item Get(int p);
}
public class BusinessLogic
{
private readonly IDataFacade facade;
public BusinessLogic(IDataFacade facade)
{
this.facade = facade;
}
public Item Get(int p)
{
return this.facade.Get(p);
}
}