Pass complex parameters to [Theory] - c#

Xunit has a nice feature: you can create one test with a Theory attribute and put data in InlineData attributes, and xUnit will generate many tests, and test them all.
I want to have something like this, but the parameters to my method are not 'simple data' (like string, int, double), but a list of my class:
public static void WriteReportsToMemoryStream(
IEnumerable<MyCustomClass> listReport,
MemoryStream ms,
StreamWriter writer) { ... }

There are many xxxxData attributes in XUnit. Check out for example the MemberData attribute.
You can implement a property that returns IEnumerable<object[]>. Each object[] that this method generates will be then "unpacked" as a parameters for a single call to your [Theory] method.
See i.e. these examples from here
Here are some examples, just for a quick glance.
MemberData Example: just here at hand
public class StringTests2
{
[Theory, MemberData(nameof(SplitCountData))]
public void SplitCount(string input, int expectedCount)
{
var actualCount = input.Split(' ').Count();
Assert.Equal(expectedCount, actualCount);
}
public static IEnumerable<object[]> SplitCountData =>
new List<object[]>
{
new object[] { "xUnit", 1 },
new object[] { "is fun", 2 },
new object[] { "to test with", 3 }
};
}
XUnit < 2.0: Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.
ClassData Example
public class StringTests3
{
[Theory, ClassData(typeof(IndexOfData))]
public void IndexOf(string input, char letter, int expected)
{
var actual = input.IndexOf(letter);
Assert.Equal(expected, actual);
}
}
public class IndexOfData : IEnumerable<object[]>
{
private readonly List<object[]> _data = new List<object[]>
{
new object[] { "hello world", 'w', 6 },
new object[] { "goodnight moon", 'w', -1 }
};
public IEnumerator<object[]> GetEnumerator()
{ return _data.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
}
XUnit >= 2.0: Instead of ClassData, now there's an 'overload' of [MemberData] that allows to use static members from other classes. Examples below have been updated to use it, since XUnit < 2.x is pretty ancient now.
Another option is ClassData, which works the same, but allows to easily share the 'generators' between tests in different classes/namespaces, and also separates the 'data generators' from the actual test methods.
MemberData Example: look there to another type
public class StringTests3
{
[Theory, MemberData(nameof(IndexOfData.SplitCountData), MemberType = typeof(IndexOfData))]
public void IndexOf(string input, char letter, int expected)
{
var actual = input.IndexOf(letter);
Assert.Equal(expected, actual);
}
}
public class IndexOfData : IEnumerable<object[]>
{
public static IEnumerable<object[]> SplitCountData =>
new List<object[]>
{
new object[] { "hello world", 'w', 6 },
new object[] { "goodnight moon", 'w', -1 }
};
}
Disclaimer :)
Last time checked #20210903 with dotnetfiddle.net on C# 5.0 and xunit 2.4.1 .. and failed. I couldn't mix-in a test-runner into that fiddle. But at least it compiled fine. Note that this was originally written years ago, things changed a little. I fixed them according to my hunch and comments. So.. it may contain inobvious typos, otherwise obvious bugs that would instantly pop up at runtime, and traces of milk & nuts.

Suppose that we have a complex Car class that has a Manufacturer class:
public class Car
{
public int Id { get; set; }
public long Price { get; set; }
public Manufacturer Manufacturer { get; set; }
}
public class Manufacturer
{
public string Name { get; set; }
public string Country { get; set; }
}
We're going to fill and pass the Car class to a Theory test.
So create a 'CarClassData' class that returns an instance of the Car class like below:
public class CarClassData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] {
new Car
{
Id=1,
Price=36000000,
Manufacturer = new Manufacturer
{
Country="country",
Name="name"
}
}
};
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
It's time for creating a test method(CarTest) and define the car as a parameter:
[Theory]
[ClassData(typeof(CarClassData))]
public void CarTest(Car car)
{
var output = car;
var result = _myRepository.BuyCar(car);
}
**If you're going to pass a list of car objects to Theory then change the CarClassData as follow:
public class CarClassData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] {
new List<Car>()
{
new Car
{
Id=1,
Price=36000000,
Manufacturer = new Manufacturer
{
Country="Iran",
Name="arya"
}
},
new Car
{
Id=2,
Price=45000,
Manufacturer = new Manufacturer
{
Country="Torbat",
Name="kurosh"
}
}
}
};
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
And the theory will be:
[Theory]
[ClassData(typeof(CarClassData))]
public void CarTest(List<Car> cars)
{
var output = cars;
}
Good Luck

To update #Quetzalcoatl's answer: The attribute [PropertyData] has been superseded by [MemberData] which takes as argument the string name of any static method, field, or property that returns an IEnumerable<object[]>. (I find it particularly nice to have an iterator method that can actually calculate test cases one at a time, yielding them up as they're computed.)
Each element in the sequence returned by the enumerator is an object[] and each array must be the same length and that length must be the number of arguments to your test case (annotated with the attribute [MemberData] and each element must have the same type as the corresponding method parameter. (Or maybe they can be convertible types, I don't know.)
(See release notes for xUnit.net March 2014 and the actual patch with example code.)

Creating anonymous object arrays is not the easiest way to construct the data so I used this pattern in my project.
First define some reusable, shared classes:
//http://stackoverflow.com/questions/22093843
public interface ITheoryDatum
{
object[] ToParameterArray();
}
public abstract class TheoryDatum : ITheoryDatum
{
public abstract object[] ToParameterArray();
public static ITheoryDatum Factory<TSystemUnderTest, TExpectedOutput>(TSystemUnderTest sut, TExpectedOutput expectedOutput, string description)
{
var datum= new TheoryDatum<TSystemUnderTest, TExpectedOutput>();
datum.SystemUnderTest = sut;
datum.Description = description;
datum.ExpectedOutput = expectedOutput;
return datum;
}
}
public class TheoryDatum<TSystemUnderTest, TExpectedOutput> : TheoryDatum
{
public TSystemUnderTest SystemUnderTest { get; set; }
public string Description { get; set; }
public TExpectedOutput ExpectedOutput { get; set; }
public override object[] ToParameterArray()
{
var output = new object[3];
output[0] = SystemUnderTest;
output[1] = ExpectedOutput;
output[2] = Description;
return output;
}
}
Now your individual test and member data is easier to write and cleaner...
public class IngredientTests : TestBase
{
[Theory]
[MemberData(nameof(IsValidData))]
public void IsValid(Ingredient ingredient, bool expectedResult, string testDescription)
{
Assert.True(ingredient.IsValid == expectedResult, testDescription);
}
public static IEnumerable<object[]> IsValidData
{
get
{
var food = new Food();
var quantity = new Quantity();
var data= new List<ITheoryDatum>();
data.Add(TheoryDatum.Factory(new Ingredient { Food = food } , false, "Quantity missing"));
data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity } , false, "Food missing"));
data.Add(TheoryDatum.Factory(new Ingredient { Quantity = quantity, Food = food } , true, "Valid" ));
return data.ConvertAll(d => d.ToParameterArray());
}
}
}
The string Description property is to throw yourself a bone when one of your many test cases fail.

You can try this way:
public class TestClass {
bool isSaturday(DateTime dt)
{
string day = dt.DayOfWeek.ToString();
return (day == "Saturday");
}
[Theory]
[MemberData("IsSaturdayIndex", MemberType = typeof(TestCase))]
public void test(int i)
{
// parse test case
var input = TestCase.IsSaturdayTestCase[i];
DateTime dt = (DateTime)input[0];
bool expected = (bool)input[1];
// test
bool result = isSaturday(dt);
result.Should().Be(expected);
}
}
Create another class to hold the test data:
public class TestCase
{
public static readonly List<object[]> IsSaturdayTestCase = new List<object[]>
{
new object[]{new DateTime(2016,1,23),true},
new object[]{new DateTime(2016,1,24),false}
};
public static IEnumerable<object[]> IsSaturdayIndex
{
get
{
List<object[]> tmp = new List<object[]>();
for (int i = 0; i < IsSaturdayTestCase.Count; i++)
tmp.Add(new object[] { i });
return tmp;
}
}
}

For my needs I just wanted to run a series of 'test users' through some tests - but [ClassData] etc. seemed overkill for what I needed (because the list of items was localized to each test).
So I did the following, with an array inside the test - indexed from the outside:
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public async Task Account_ExistingUser_CorrectPassword(int userIndex)
{
// DIFFERENT INPUT DATA (static fake users on class)
var user = new[]
{
EXISTING_USER_NO_MAPPING,
EXISTING_USER_MAPPING_TO_DIFFERENT_EXISTING_USER,
EXISTING_USER_MAPPING_TO_SAME_USER,
NEW_USER
} [userIndex];
var response = await Analyze(new CreateOrLoginMsgIn
{
Username = user.Username,
Password = user.Password
});
// expected result (using ExpectedObjects)
new CreateOrLoginResult
{
AccessGrantedTo = user.Username
}.ToExpectedObject().ShouldEqual(response);
}
This achieved my goal, while keeping the intent of the test clear. You just need to keep the indexes in sync but that's all.
Looks nice in the results, it's collapsable and you can rerun a specific instance if you get an error:

This is how I solved your problem, I had the same scenario. So inline with custom objects and a different number of objects on each run.
[Theory]
[ClassData(typeof(DeviceTelemetryTestData))]
public async Task ProcessDeviceTelemetries_TypicalDeserialization_NoErrorAsync(params DeviceTelemetry[] expected)
{
// Arrange
var timeStamp = DateTimeOffset.UtcNow;
mockInflux.Setup(x => x.ExportTelemetryToDb(It.IsAny<List<DeviceTelemetry>>())).ReturnsAsync("Success");
// Act
var actual = await MessageProcessingTelemetry.ProcessTelemetry(JsonConvert.SerializeObject(expected), mockInflux.Object);
// Assert
mockInflux.Verify(x => x.ExportTelemetryToDb(It.IsAny<List<DeviceTelemetry>>()), Times.Once);
Assert.Equal("Success", actual);
}
So this is my unit test, notice the params parameter. This allow to send a different number of object. And now my DeviceTelemetryTestData class :
public class DeviceTelemetryTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
yield return new object[] { new DeviceTelemetry { DeviceId = "asd" }, new DeviceTelemetry { DeviceId = "qwe" } };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Hope it helps !

Despite this has already been answered I just want to add an improvement here.
The restriction of passing objects in InlineData attribute is not a limitiation of xUnit itself but C# attributes.
See this compiler error: Compiler Error CS0182

xUnit.Sdk provides you with DataAttribute class that you could inherit and override its GetData method and use it to pass whatever you feel like you want..
I usually use it alongside DataTestBuilders pattern and build something like that..
public class ValidComplexObjectDataSource : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] {
ComplexObjectBuilder
.BasicComplexObject()
.Build()
};
yield return new object[] {
ComplexObjectBuilder
.BasicComplexObject()
.WithoutSomeAttribute()
.Build()
};
// ... list all test cases you want to pass to your method
}
}
This ComplexObjectBuilder could be whatever your object is, highly recommend checking builder pattern
[Theory]
[Trait("Validation", "CreateXYZCommand")]
[ValidComplexObjectDataSource]
public void CreateXYZCommandValidator_WithValidInput_ShouldPassAllValidations(CreateComplexObjectInput createComplexObjectInput)
{
var command = new CreateXYZCommand(createComplexObjectInput);
var result = _validator.TestValidate(command);
result.ShouldNotHaveAnyValidationErrors();
}
I only demonstrated it with a single object, you have an array of objects you can yield.
yield return new object[] {
ComplexObject_1,
ComplexObject_2,
string_attribute,
int_attribute
};
and have these as arguments to your test cases.

You can utilize TheoryData for complex types like classes.
[Theory, MemberData(nameof(CustomClassTests))]
public async Task myTestName(MyCustomClass customClassTestData) { ... }
public record MyCustomClass { ... }
public static TheoryData<MyCustomClass> CustomClassTests {
get {
return new() {
new MyCustomClass{ ... },
new MyCustomClass{ ... },
...
};
}
}

I guess you mistaken here. What xUnit Theory attribute actually means: You want to test this function by sending special/random values as parameters that this function-under-test receives. That means that what you define as the next attribute, such as: InlineData, PropertyData, ClassData, etc.. will be the source for those parameters. That means that you should construct the source object to provide those parameters. In your case I guess you should use ClassData object as source. Also - please note that ClassData inherits from: IEnumerable<> - that means each time another set of generated parameters will be used as incoming parameters for function-under-test until IEnumerable<> produces values.
Example here: Tom DuPont .NET
Example may be incorrect - I didn't use xUnit for a long time

Related

Complex IEnumerable Result from LINQ Select

I'm trying to understand the resultant type from a LINQ select action. I'm having trouble understanding how to utilize the result.
Consider the following:
public class ReportContract
{
public int ContractId { get; set; }
public string ContractName { get; set; }
public string Title { get; set; }
public string[] Details { get; set; }
}
public class ReportContractVM
{
public int ContactId { get; set; }
public string ContractName { get; set; }
}
public class SomeController : ControllerBase
{
public ActionResult<IEnumerable<ReportContractVM>> Get()
{
IEnumerable<ReportContract> contracts = CreateConrtacts();
IEnumerable<ReportContractVM> result = contracts.Select(
x => new ReportContractVM
{
ContactId = x.ContractId,
ContractName = x.ContractName
}
);
return Ok(result);
}
private IEnumerable<ReportContract> CreateContracts()
{
List<ReportContract> contracts = new List<ReportContract>()
{
new ReportContract {
ContractId = 1234,
ContractName= "ABCD",
Details= new string[] {
"test", "Best", "rest", "jest"},
Title="First"
},
new ReportContract {
ContractId = 1235,
ContractName= "EFGH",
Details= new string[] {
"fish", "dish", "wish", "pish"},
Title="Second"
},
new ReportContract {
ContractId = 1236,
ContractName= "IJKL",
Details= new string[] {
"hot", "tot", "mot", "jot"},
Title="Third"
},
new ReportContract {
ContractId = 1237,
ContractName= "MNOP",
Details= new string[] {
"ring", "sing", "bing", "ping"},
Title="Fourth"
}
};
return contracts;
}
}
Inspecting the type assigned to 'result' in the debugger yields:
System.Linq.Enumberable.SelectListIterator
<
ComplexIEnumerable.ReportContract,
ComplexIEnumerable.ReportContractVM
>
I am not sure how this relates to
IEnumerable<ReportContractVM>.
How is
IEnumerable<ReportContractVM>
accessed from this result?
Please ignore the rest of this text. The "intelligent" editor is demanding more detail and I think this suffices.
I recommend reading this article that explains what Enumerator (aka yield return methods) materialization is - as it's core to how Linq works and how to use IEnumerable<T> results (note that an IEnumerable<T> can refer to a both materialized collections like T[] or List<T> and also non-materialized enumerators):
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/intermediate-materialization
As for your case, generally speaking, never return a non-materialized Entity Framework (i.e. database-backed) IEnumerable<T> or IQueryable<T> from an ASP.NET Web API Controller or pass a non-materialized IEnumerable<T> as a member of a ViewModel (this is because the lifetime of the parent DbContext may be shorter than the lifetime of the IEnumerable<T>/IQueryable<T> object). However returning an non-materialized collection using only in-memory objects is fine (such as an enumerator over enum values to get SelectListItem objects):
Specifically, change this:
IEnumerable<ReportContractVM> result = contracts.Select(
x => new ReportContractVM
{
ContactId = x.ContractId,
ContractName = x.ContractName
}
);
to this:
List<ReportContractVM> list = contracts
.Select( x => new ReportContractVM { ContractId = x.ContractId, ContractName = x.ContractName } )
.ToList();
Also, change your ActionResult<T> to use IReadOnlyList<T> instead of IEnumerable<T> which will help ensure you always return a materialized list instead of a possibly non-materialized enumerator:
public class SomeController : ControllerBase
{
public ActionResult<IReadOnlyList<ReportContractVM>> Get()
{
}
}
BTW, I've been having problems with ActionResult<T> not working well with generics and in async Task<ActionResult<T>> actions so I personally prefer to do this, but YMMV:
public class SomeController : ControllerBase
{
[Produces( typeof( IReadOnlyList<ReportContractVM> ) )
public IActionResult Get()
{
}
// if async:
[Produces( typeof( IReadOnlyList<ReportContractVM> ) )
public async Task<IActionResult> Get()
{
}
}
Basically the output is the concrete enumerable type returned from Select with type parameters referencing both the input and output types. It may be easier to see in a simplified example below.
namespace ExampleNamespace
{
class A
{
public A(int i) { }
}
}
Now say I have this code somewhere:
List<int> i = new List<int>() { 1, 2, 3, 4, 5, 6 };
var temp = i.Select(x => new A(x));
Upon inspection the type of temp is:
System.Linq.Enumerable.WhereSelectListIterator<int, ExampleNamespace.A>
So to break this down:
System.Linq.Enumerable.WhereSelectListIterator is the type of iterator returned from Select. This differs from your type slightly probably due to different .NET versions.
int is the the type that your starting IEnumerable held
ExampleNamespace.A is the full name of the output type.
That all being said, you should read and understand what Dai posted in their answer.

Get values out of collections with FastMember

I use FastMember to get values out of objects and nested objects. If a property is a string or int everything works fine. But now I want to get the values also for collections. Here is my code so far:
// Set accessor
var sourceAccessor = ObjectAccessor.Create(source);
if (sourceAccessor.Target.GetType().GetInterface(nameof(ICollection)) != null || sourceAccessor.Target.GetType().GetInterface(nameof(IEnumerable)) != null)
{
foreach (/* idk */)
{
// READ & RETURN VALUES HERE
}
}
An object could look like this:
{
Id: 1,
Surname: Doe,
Prename: John,
Professions: [
{ Name: ab },
{ Name: xy }
]
}
Which means professions would result in a problem.
Any advise how I can solve this problem? Thanks!
It's not obvious from the question what the data type of the source variable is, but you should just be able to check if the value returned by the accessor implements IEnumerable or not and act accordingly.
Here's a quick worked example that iterates over the Professions property of a 'Person' object and just dumps the ToString() representation to the console - if you wanted to dive into each Profession object using FastMember you could construct another ObjectAccessor to do it, I guess - it's not clear what your goal is once you're iterating.
The same tactic will work if you're building the ObjectAccessor directly from an array - you just check if the accessor.Target is IEnumerable and cast-and-iterate in a similar fashion.
class Program
{
static void Main(string[] args)
{
var p = new Person
{
Professions = new List<Profession>
{
new Profession("Joker"),
new Profession("Smoker"),
new Profession("Midnight toker")
}
};
var accessor = ObjectAccessor.Create(p);
var professions = accessor[nameof(Person.Professions)];
if (professions is IEnumerable)
{
foreach (var profession in (IEnumerable)professions)
{
Console.WriteLine(profession);
}
}
}
}
class Person
{
public List<Profession> Professions { get; set; }
}
class Profession
{
public string Name { get; set; }
public Profession( string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}

How to add to a read-only 'List' property in class defined using expression body?

When I run the code below the 'Works' property on TestHelper returns 4 Test items as it should but the 'Fails' property only returns 1 Test item.
Sample Classes:
public class Test {
public string Name { get; set; }
}
public class TestHelper {
public TestHelper() {
AddTest(new Test() { Name = "1" });
}
public List<Test> Works { get; } = new List<Test>() {
new Test(){ Name="0"}
};
public List<Test> Fails => new List<Test>() {
new Test(){ Name="0"}
};
public TestHelper AddTest(Test test) {
Works.Add(test);
Fails.Add(test);
return this;
}
}
Sample Program:
var th = new TestHelper();
th.AddTest(new Test { Name = "2" });
th.Works.Add(new Test { Name = "3" });
th.Fails.Add(new Test { Name = "4" });
var json = Newtonsoft.Json.JsonConvert.SerializeObject(th);
Json Results:
{
"Works":[{"Name":"0"},{"Name":"1"},{"Name":"2"},{"Name":"3"}],
"Fails":[{"Name":"0"}]
}
Both the 'Works' & 'Fails' look to be defined as read-only List properties of Test.
Why does one definition method work and not the other?
Works is a read-only auto-implemented property with a default value, equivalent to this:
private List<Test> _works = new List<Test>() { new Test() { Name="0" } };
public List<Test> Works { get { return _works; } }
The value of Works is initialized once, when it is created. You are subsequently making modifications to the list by adding values - note that the property is read-only, not the List that it contains.
By contrast, Fails is a property whose getter returns a newly-created list every time you get it. It is equivalent to this:
public List<Test> Fails
{
get
{
return new List<Test>() { new Test() { Name = "0" } };
}
}

How to set the return value for an IEnumerable class using NSubstitute

I have this domain:
public class ADomainClass
{
public int Id { get; set; }
}
public interface IMyClass : IEnumerable<ADomainClass>
{
}
public class MyClass : IMyClass
{
public IEnumerator<ADomainClass> GetEnumerator()
{
IList<ADomainClass> list = new List<ADomainClass>();
//list = GetData...();
foreach (var item in list)
{
yield return item;
}
}
...
}
and want to build the following test:
[Test]
public void TestSample()
{
//Arrange
IMyClass myclass = Substitute.For<IMyClass>();
IList<ADomainClass> testdata = new List<ADomainClass>()
{
new ADomainClass(){ Id = 1, },
new ADomainClass(){ Id = 2, },
new ADomainClass(){ Id = 3, },
new ADomainClass(){ Id = 4, },
};
int count = 0;
myclass.ReturnsForAnyArgs(testdata); //How to set the "return" value?
//Act
foreach (ADomainClass item in myclass)
{
count++;
}
//Assert
count.Should().Be(testdata.Count);
}
Setting the return value for a method is easy and would look like this:
myclass.GetData().Returns(data);
I can't remember how to set the return value when it is an enumerable class. I have solved this once before, but can't remember where I have used it.
My problem was that NSubstitute stores the state of the enum, so if you use the Enumerator twice in the system under test, it will continue with the second element at the second time. I am using something like the code below as a workaround (using a lambda instead of returning the Enumerator, lines 1 + 2 are for demonstration only). I have only tested this with some Linq and foreach.
var bar = new List<string> { "a", "b", "c" };
var foo = Substitute.For<ICollection<string>>();
foo.GetEnumerator().Returns((ci) => { return bar.GetEnumerator(); });
You just need to tell your substitute to return the enumerator from you test data:
myclass.GetEnumerator().Returns(testdata.GetEnumerator());

RelationPredicateBucket doesn't filter mocked data for Unit Test on Repository GetAllActive() call

I am trying to Test a function which I have below to get all active categories which will use a relation predicate bucket. The mocked data in the initializer class adds three objects which are both active and not deleted. It adds a fourth to the end which is deleted and not active.
During the test, the call will return all four objects, and not the expected number of three. This is where I am stuck with.
I have tried making _randomCategories as a Queryable object, but this also failed.
There is a lot of code in the first class so it may be hard to follow, so each part is broken into regions saying which part it performs, i.e. Test Setup, Mock Data, & the Tests themselves.
The Mock Data region are the expected results. May not be necessary for my needs here as it is not used in this other than to get the expected count, but it may be relevant to the overall structure of the tests.
CategoryServiceTests.cs
#region Test Setup
public class CategoryServiceFixture : IDisposable
{
public CategoryService Sut { get; private set; }
private SystemRepository SystemRepository { get; set; }
private Mock<CategoryRepository> _categoryRepositoryMock;
private List<CategoryEntity> _randomCategories;
public CategoryServiceFixture()
{
// Init Category List
_randomCategories = CategoryEntityInitializer.GetAllMockCategories();
// Init repository
_categoryRepositoryMock = new Mock<CategoryRepository>(new object[] { null });
// Setup mocking behavior
// BaseRepository
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(_randomCategories);
SystemRepository = new SystemRepository(category: _categoryRepositoryMock.Object);
Sut = new CategoryService(this.SystemRepository);
}
public void Dispose()
{
//Sut.Dispose();
}
}
[CollectionDefinition("CategoryService Collection")]
public class CategoryServiceCollection : ICollectionFixture<CategoryServiceFixture> { }
#endregion
#region Mock Data
public static class CategoryRepositoryMockData
{
public static IEnumerable<object> GetCategories
{
get
{
yield return new object[] { 1, new List<CategoryEntity>() {
new CategoryEntity
{
CategoryId = 1,
Name = "Test1",
IsDeleted = false,
IsActive = true
},
new CategoryEntity
{
CategoryId = 2,
Name = "Test2",
IsDeleted = false,
IsActive = true
},
new CategoryEntity
{
CategoryId = 3,
Name = "Test3",
IsDeleted = false,
IsActive = true
}
}};
}
}
}
#endregion
#region Tests
[Collection("CategoryService Collection")]
public class CategoryServiceTests
{
private CategoryServiceFixture _fixture;
public CategoryServiceTests(CategoryServiceFixture fixture)
{
_fixture = fixture;
}
[Theory]
[Trait("Category", "Get All Active Categories")]
[Trait("Expected", "Return Correct")]
[MemberData("GetCategories", MemberType = typeof(CategoryRepositoryMockData))]
public void GetActiveCategories_ShouldReturn(int id, IList<CategoryEntity> expectedCategoryObjects)
{
var result = _fixture.Sut.GetActiveCategories();
Assert.Equal(expectedCategoryObjects.Count, result.Count);
}
}
#endregion
This class generates the mock database objects. This is what is supposed to be searched through and select the correct ones from the list.
CategoryEntityInitializer.cs
public static class CategoryEntityInitializer
{
public static List<CategoryEntity> GetAllMockCategories()
{
List<CategoryEntity> _categories = new List<CategoryEntity>();
for (var i = 1; i <= 3; i++)
{
var entity = new CategoryEntity()
{
CategoryId = i,
Name = String.Format("{0}{1}", "Test", i),
IsDeleted = false,
IsActive = true
};
_categories.Add(entity);
}
var lastEntity = new CategoryEntity()
{
CategoryId = 4,
Name = String.Format("{0}{1}", "Test", 4),
IsDeleted = true,
IsActive = false
};
_categories.Add(lastEntity);
return _categories;
}
}
This class is where the predicate is.
CategoryService.cs
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
}
The rest of the code structure works fine for every other test and across different test classes. This is the first time I have had to test the relation predicate bucket.
UPDATE 18/05/16
I found the solution to the problem. Answer in the below code.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(new Func<IRelationPredicateBucket, IDataAccessAdapter, IEnumerable<CategoryEntity>>(
(bucket, adapter) => _randomCategories.Where(a => a.IsDeleted == false && a.IsActive == true)));
Old Answer 11/05/16
I believe I have found part of the answer. In mocking the repository, I was returning all four objects, no matter if the predicate bucket would work or not.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(_randomCategories);
This will cause it to return all four as I have not implemented the bucket to filter out the matches. I thought that the .Returns would place the data into the repository as if returned from the database and then get filtered with the bucket.
What I have found out is that the call to the repository does not go to the one it would if it was running normally, but instead goes to the mocked repository and this is where you need to filter the data to be returned.
It needs to be done something similar to this.
_categoryRepositoryMock
.Setup(m => m.GetAll(It.IsAny<IRelationPredicateBucket>(), It.IsAny<IDataAccessAdapter>()))
.Returns(
(IRelationPredicateBucket bucket) => _randomCategories.Where(x => x.Name.Equals(bucket)));
Although this still give me a problem as I don't know how to get inside the bucket to match to the list, it is at least heading in the correct direction.
NOTE: I have also found from searching that another reason for this type of failure is due to the code, in this case the function being called is too complex to be tested. It should be seperated into smaller chucks to make it less complex and to test each part seperately.
Before
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
}
After
public class CategoryService : BaseService
{
public IList<CategoryModel> GetActiveCategories()
{
var bucket = GetActiveCategoriesBucket();
var categoriesEntities = _systemRepository.Category.GetAll(bucket);
return CategoryMapper.MapToModels(categoriesEntities);
}
public RelationPredicateBucket GetActiveCategoriesBucket()
{
var bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(CategoryFields.IsDeleted == false);
bucket.PredicateExpression.Add(CategoryFields.IsActive == true);
return bucket;
}
}

Categories