Mock a Custom Collection using Moq - c#

I have the following types in a 3rd party library
public interface IWorkbook : IPrintable
{
...
IWorksheets Worksheets { get; }
}
The worksheets interface is
public interface IWorksheets : IEnumerable
{
IWorksheet this[int index] { get; }
IWorksheet this[string name] { get; }
IWorkbookSet WorkbookSet { get; }
IWorksheet Add();
IWorksheet AddAfter(ISheet sheet);
IWorksheet AddBefore(ISheet sheet);
bool Contains(IWorksheet worksheet);
}
I have a method that I want to unit test that takes an IWorkbook and iterates through the contained worksheets. My problem is how I can use Moq to create a mock collection for IWorksheets. The IWorksheet interface is
public IWorksheet
{
...
public Name { get; set; } // This is the only property I am interested in.
}
So how can I generate a fake IWorkbook which has a fake collection (IWorksheets) of IWorksheets?
I have started out with
[TestInitialize]
public void Initialize()
{
List<string> fakeSheetNames = new List<string>()
{
"Master",
"A",
"B",
"C",
"__ParentA",
"D",
"wsgParentB",
"E",
"F",
"__ParentC",
"__ParentD",
"G"
};
List<IMock<IWorksheet>> sheetMockList = new List<IMock<IWorksheet>>();
foreach (string name in fakeSheetNames)
{
Mock<IWorksheet> tmpMock = new Mock<IWorksheet>();
tmpMock.Setup(p => p.Name).Returns(name);
sheetMockList.Add(tmpMock);
}
var mockWorksheets = new Mock<IWorksheets>();
mockWorksheets.Setup(p => p).Returns(sheetMockList);
...
}
But I cannot do this as (obviously)
cannot convert from 'System.Collections.Generic.List>' to 'SpreadsheetGear.IWorksheets'
How can I mock the IWorksheets collection?
So I now have the following code to create my mocks as per the answer below
[TestClass]
public class WorkbookStrucutreProviderTests
{
private Mock<IWorkbookSet> mockWorkbookSet;
private readonly List<string> parentPrefixes = new List<string>() { "__", "wsg" };
[TestInitialize]
public void Initialize()
{
List<string> fakeSheetNames = new List<string>()
{
"Master",
"A",
"B",
"C",
"__ParentA",
"D",
"wsgParentB",
"E",
"F",
"__ParentC",
"__ParentD",
"G"
};
List<IWorksheet> worksheetMockList = new List<IWorksheet>();
foreach (string name in fakeSheetNames)
{
Mock<IWorksheet> tmpMock = new Mock<IWorksheet>();
tmpMock.Setup(p => p.Name).Returns(name);
tmpMock.Setup(p => p.Visible)
.Returns(parentPrefixes.Any(p => name.StartsWith(p)) ?
SheetVisibility.Hidden :
SheetVisibility.Visible);
worksheetMockList.Add(tmpMock.Object);
}
List<IWorkbook> workbookMockList = new List<IWorkbook>();
Mock<IWorkbook> mockWorkbook = new Mock<IWorkbook>();
mockWorkbook
.Setup(p => p.Worksheets.GetEnumerator())
.Returns(worksheetMockList.GetEnumerator());
workbookMockList.Add(mockWorkbook.Object);
mockWorkbookSet = new Mock<IWorkbookSet>();
mockWorkbookSet
.Setup(p => p.Workbooks.GetEnumerator())
.Returns(workbookMockList.GetEnumerator());
}
[TestMethod]
public async Task StrucutreGenerationAsyncTest()
{
WorkbookStructureProvider provider = new WorkbookStructureProvider();
await provider.GenerateWorkbookStructureAsync(mockWorkbookSet.Object);
foreach (var item in provider.Structure)
{
Trace.WriteLine("--" + item.Name);
if (item.HasChildren)
{
foreach (var child in item.Children)
{
Trace.WriteLine("-- --" + child.Name);
}
}
}
}
But in the GenerateWorkbookStructureAsync() method I have this bit of code
bool IsUserCostWorkbook = false;
if (workbook.Worksheets.Cast<IWorksheet>().Any(
ws => ws.Name.CompareNoCase(Keywords.Master)))
{
// TODO Extra check for UserCost template.
IsUserCostWorkbook = true;
}
and here the workbook.Worksheets collection is empty. I thought my mock GetEnumerator would handle this; it doesn't.
So how can I mock the IWorksheets so that I can do the following?
foreach (var ws in workbook.Worksheets.Cast<IWorksheet>())
{
...
}

The following example passes when tested
[TestMethod]
public void Mock_Custom_Collection_Using_Moq() {
//Arrange
var parentPrefixes = new List<string>() { "__", "wsg" };
var fakeSheetNames = new List<string>(){
"Master",
"A",
"B",
"C",
"__ParentA",
"D",
"wsgParentB",
"E",
"F",
"__ParentC",
"__ParentD",
"G"
};
var worksheetMockList = new List<IWorksheet>();
foreach (string name in fakeSheetNames) {
var worksheet = Mock.Of<IWorksheet>();
worksheet.Name = name;
worksheet.Visible = parentPrefixes.Any(p => name.StartsWith(p)) ?
SheetVisibility.Hidden :
SheetVisibility.Visible;
worksheetMockList.Add(worksheet);
}
var mockWorkbook = new Mock<IWorkbook>();
mockWorkbook
.Setup(p => p.Worksheets.GetEnumerator())
.Returns(() => worksheetMockList.GetEnumerator());
var workbook = mockWorkbook.Object;
//Act
bool IsUserCostWorkbook = false;
if (workbook.Worksheets.Cast<IWorksheet>()
.Any(ws => ws.Name.Equals("Master", StringComparison.InvariantCultureIgnoreCase))) {
IsUserCostWorkbook = true;
}
//Assert
Assert.IsTrue(IsUserCostWorkbook);
}

Sorry for pseudo code:
var fakeWorksheet = new Mock<IWorksheet>();
//You can use AutoFixture here to auto-populate properties or you can set only required props
fakeWorksheet.Setup(p => p.Name).Returns("TestName");
var worksheetsMock = new Mock<IWorksheets>()
//here mock some members that you need
worksheetsMock.Setup(w => w.Add()).Returns(fakeWorksheet.Object);
var workbookMock = new Mock<IWorkbook>();
workbookMock.Setup(w => w.Worksheets).Returns(worksheetsMock.Object);

Related

Create a list with specific values with Autofixture C#

The Model has properties Id, Code etc.
I want to create 4 data with specific different codes.
var data = _fixture.Build<MyModel>()
.With(f => f.Code, "A")
.CreateMany(4);
This results in all 4 data with Code "A". I want the 4 data to have codes "A", "B", "C", "D"
Thanks in Advance
There is an easier way to do this
string[] alphabets = { "A", "B", "C", "D" };
var queue = new Queue<string>(alphabets);
var data = _fixture.Build<MyModel>()
.With(f => f.Code, () => queue.Dequeue())
.CreateMany(alphabets.Length);
Output
[
{Code: "A"},
{Code: "B"},
{Code: "C"},
{Code: "D"}
]
In case if you want the result in reverse order use Stack instead of Queue and Pop instead of Dequeue
Assuming you only need 4 items you can define your collection of codes and use it to generate the 4 models using LINQ.
public static object[][] Codes =
{
new object[] { new[] { "A", "B", "C", "D" } }
};
[Theory]
[MemberAutoData(nameof(Codes))]
public void Foo(string[] codes, Fixture fixture)
{
var builder = fixture.Build<MyModel>(); // Do any other customizations here
var models = codes.Select(x => builder.With(x => x.Code, x).Create());
var acutal = models.Select(x => x.Code).ToArray();
Assert.Equal(codes, acutal);
}
public class MyModel
{
public int Id { get; set; }
public string Code { get; set; }
}
This seems ripe for an extension method:
public static IPostprocessComposer<T> WithValues<T, TProperty>(this IPostprocessComposer<T> composer,
Expression<Func<T, TProperty>> propertyPicker,
params TProperty[] values)
{
var queue = new Queue<TProperty>(values);
return composer.With(propertyPicker, () => queue.Dequeue());
}
// Usage:
var data = _fixture.Build<MyModel>()
.WithValues(f => f.Code, "A", "B", "C", "D")
.CreateMany(4);

Moq keeps throwing null reference exception

I am new to Moq having used Rhino mocks for a while. I am trying to stub a method so that is returns the information I expect but the actual line of code when running the test returns a null reference exception. Am I missing something obvious here? Below is my code:
public void GetResSystemClients(ResSystem resSystem)
{
ResSystemDetail = new ResSystemDetails() {ResSys = resSystem};
//RETURNS NULL REFERENCE EXCEPTION
var resClients = FileReader.ReadFile((c) => c.Where(x =>
x.ReservationSystem.Replace(" ", "").ToLowerInvariant().Contains(resSystem.ToString().ToLowerInvariant())));
ResSystemDetail.ResSystemClients = resClients
.Select(y => new ResSystemClient() {ClientCode = y.ClientCode, ClientName = y.ClientName})
.OrderBy(z => z.ClientCode).ToList();
}
Test Code
[SetUp]
public void SetUp()
{
mockFileReader = new Mock<IClientLookUpFileReader>(MockBehavior.Default);
sut = new ClientLookupModel();
}
[TestCase(ResSystem.Test)]
public void When_GetResSystemCalled_With_ResSystem_Return_CorrectClients(ResSystem system)
{
//Arrange
mockFileReader.Setup(x =>
x.ReadFile(It.IsAny<Func<List<ExtraClientInfo>, IEnumerable<ExtraClientInfo>>>()))
.Returns(new List<ExtraClientInfo>
{
new ExtraClientInfo
{
ClientName = "Test",
ClientCode = "XX"
},
new ExtraClientInfo
{
ClientName = "Test1",
ClientCode = "X1"
},
new ExtraClientInfo
{
ClientName = "Test2",
ClientCode = "X2"
},
});
//Act
sut.GetResSystemClients(system);
}
Read file code
public interface IClientLookUpFileReader
{
T ReadFile<T>(Func<List<ExtraClientInfo>, T> predicateFunc);
}
public class ClientLookUpFileReader : IClientLookUpFileReader
{
private const string filePath = "D:/PersistedModels/ClientInfo.json";
T IClientLookUpFileReader.ReadFile<T>(Func<List<ExtraClientInfo>, T> predicateFunc)
{
if (File.Exists(filePath))
{
var clientInfoList = new JavaScriptSerializer().Deserialize<List<ExtraClientInfo>>(System.IO.File.ReadAllText(filePath));
return predicateFunc(clientInfoList);
}
throw new Exception($"File not found at path {filePath}");
}
}

Moq Insert/Update with new Object initialization

public class UserService
{
IUserRepo userRepo;
UserService(IUserRepo repo)
{
userRepo = repo;
}
void AddUser(JsonData data)
{
User user = new User()
{
Name = data.name,
Number = data.Number
};
userRepo.Insert(user);
int id = user.id;
}
}
id is 0 when a unit test case is debugged, but when it is a proper call it returns proper primary key i.e. 1, 2, 3, etc.
Mock
class TestCases
{
Mock<IUserRepo> mockUserRepo = new Mock<IUserRepo>();
[Test]
public void test1()
{
//Arrange
JsonData obj = new JsonData()
{
Name = "Jane",
Number = "0563722992"
}
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
mockUserRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback(() => dumpUser.Id = 1);
//Act
UserService u = new UserService(mockUserRepo.Object);
u.AddUser(obj);
//Assert
}
}
While debugging the unit test it seems that callback is unable to change the id to 1 when it passes through the method Insert().
Can anybody help how to tackle with this issue?
There is no need for
User dumpUser= new User()
{
Name = "Def",
Number = "8111"
};
As the method under test creates/initializes it's own instance within.
Capture the passed argument in the call back and update the desired member there
//...
userRepo
.Setup(x => x.Insert(It.IsAny<User>()))
.Callback((User arg) => arg.Id = 1);
//...

IEnumerable interface TDD using Mock in C# [duplicate]

This question already has answers here:
Testing a function that returns IEnumerable<string>
(2 answers)
Closed 4 years ago.
Below is the FizzBuzz Generation Code,
public class BusinessHandler : IBusinessHandler
{
private readonly IEnumerable<IBusinessRule> BusinessRule;
public BusinessHandler(IEnumerable<IBusinessRule> businessrule)
{
this.BusinessRule = businessrule;
}
public IEnumerable<string> GetResult(int inputValue)
{
var outputList = new List<string>();
for (int element = 1; element <= inputValue; element++)
{
string tempOutput = element.ToString();
var divisionResult = this.BusinessRule.FirstOrDefault(x => x.IsDivisible(element));
if (divisionResult != null)
{
tempOutput = divisionResult.PrintOutput();
}
outputList.Add(tempOutput);
}
return outputList;
}
}
Here IBusinessHandler, IBusinessRule are the interface. Using Dependency Injection, i am calling this method in my web application.
IBusinessRule :
public interface IBusinessRule
{
bool IsDivisible(int inputValue);
string PrintOutput();
}
3 classes are implementing IBusinessRule interface.
I am new to TDD, how can I implement unit test for GetResult() method.
For TDD i am using Nunit,Moq packages.
A test for the provided code can look like this
[TestClass]
public class BusinessHandlerTests {
[TestMethod]
public void BusinessHandler_Should_GetResult() {
//Arrange
var fizz = new Mock<IBusinessRule>();
fizz.Setup(_ => _.IsDivisible(It.IsAny<int>()))
.Returns((int value) => value % 3 == 0);
fizz.Setup(_ => _.PrintOutput()).Returns("Fizz");
var buzz = new Mock<IBusinessRule>();
buzz.Setup(_ => _.IsDivisible(It.IsAny<int>()))
.Returns((int value) => value % 5 == 0);
buzz.Setup(_ => _.PrintOutput()).Returns("Buzz");
var fizzbuzz = new Mock<IBusinessRule>();
fizzbuzz.Setup(_ => _.IsDivisible(It.IsAny<int>()))
.Returns((int value) => value % 15 == 0);
fizzbuzz.Setup(_ => _.PrintOutput()).Returns("FizzBuzz");
var businessRule = new[] {
fizzbuzz.Object, fizz.Object, buzz.Object // <--order is important
};
var subject = new BusinessHandler(businessRule);
var inputValue = 15;
var expected = new[] { "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz" };
//Act
var actual = subject.GetResult(inputValue);
//Assert
actual.Should().BeEquivalentTo(expected);
}
}
Assuming the business rules have not already been defined, they can be mocked and injected into the subject under test, as demonstrated above.
If for example the classes already existed
public class FizzObject : IBusinessRule {
public bool IsDivisible(int inputValue) => inputValue % 3 == 0;
public string PrintOutput() => "Fizz";
}
then they can be initialized
var businessRule = new[] { new FizzBuzzObject(), new FizzObject(), new BuzzObject() }; // <--order is important
and injected into the subject under test with the same expected behavior
You don't need mocks for testing "FizzBuzz".
As you said you have 3 implementations of IBusinessRule
public class RuleOne : IBusinessRule { ... }
public class RuleTwo : IBusinessRule { ... }
public class RuleThree : IBusinessRule { ... }
Then you can write test which cover whole logic. With this kind of test you will test BusinessHandler and all implementations of IBusinessRule will be tested as well.
With this test you will have freedom to redesign how BusinessHandler implemented (possibly need to change only constructor)
// Here used NUnit feature of TestCase to provide values to the test function
[Test]
[TestCase(1, new[] { "1" })]
[TestCase(3, new[] { "Fizz" })]
[TestCase(5, new[] { "Buzz" })]
[TestCase(15, new[] { "Fizz", "Buzz" })]
[TestCase(20, new[] { "20" })]
public void ShouldReturnExpectedResult(int input, string[] expected)
{
// Arrange
var rules = new[]
{
new RuleOne();
new RuleTwo();
new RuleThree();
}
var handler = new BusinessHandler(rules);
// Act
var actual = handler.GetResult(input);
// Assert
actual.Should().BeEquivalent(expected);
}

Elements in array of user-defined type all change when one changes [duplicate]

This question already has answers here:
Why is list when passed without ref to a function acting like passed with ref?
(8 answers)
Closed 5 years ago.
There is an illogical change happening in my array called "animals". Whenever I change one element in the array, all the other elements change along with it. I have no idea why this is happening.
When I run the program below, the console writes
Sugar, Dog
Sugar, Dog
That should not be happening. I should be getting
Fluffy, Cat
Sugar, Dog
Please look at the relevant code below:
//Program.cs
namespace AnimalProgram
{
class Program
{
static void Main(string[] args)
{
AnimalInfo vitalStats = new AnimalInfo("vital statistics", new string[] { "name", "sex", "species", "breed", "age" }); //name, species, breed, sex, age.
AnimalInfo veterinarian = new AnimalInfo("veterinarian", new string[] { "Vet Name", "Name of Vet's Practice" });
List<AnimalInfo> animalStats = new List<AnimalInfo> {vitalStats, veterinarian };
Animal cat1 = new Animal();
Animal dog1 = new Animal();
Animal[] animals = new Animal[2] { cat1, dog1};
for(int i = 0; i < animals.Count(); i++) animals[i].initializeAnimalInfo(animalStats);
AnimalInfo cat1vitals= new AnimalInfo("vital statistics", new string[] { "Fluffy", "F", "Cat", "American Shorthair", "5" });
AnimalInfo dog1vitals = new AnimalInfo("vital statistics", new string[] { "Sugar", "F", "Dog", "Great Dane", "7" });
AnimalInfo cat1vet = new AnimalInfo("veterinarian", new string[] { "Joe Schmoe", "Joe's Veterinary" });
AnimalInfo dog1vet = new AnimalInfo("veterinarian", new string[] { "Jim Blow", "Jim's Garage" });
cat1.UpdateAnimalInfo(new List<AnimalInfo>() { cat1vitals, cat1vet });
dog1.UpdateAnimalInfo(new List<AnimalInfo>() { dog1vitals, dog1vet });
Console.WriteLine(cat1.animalProperties[0].info[0] + ", " + cat1.animalProperties[0].info[2]);
Console.WriteLine(dog1.animalProperties[0].info[0] + ", " + dog1.animalProperties[0].info[2]);
Console.ReadLine();
}
}
}
//Animal.cs
using System.Collections.Generic;
using System.Linq;
namespace AnimalProgram
{
class Animal
{
public List<AnimalInfo> animalProperties;
public Animal() { }
public void initializeAnimalInfo(List<AnimalInfo> aInfo)
{
animalProperties = aInfo;
}
public void UpdateAnimalInfo(List<AnimalInfo> targetInfo)
{
for (int i = 0; i < targetInfo.Count(); i++)
animalProperties[i].info = targetInfo[i].info;
}
}
}
//AnimalInfo.cs
namespace AnimalProgram
{
public class AnimalInfo
{
public string infoName;
public string [] info;
public AnimalInfo(string iName, string [] information)
{
infoName = iName;
info = information;
}
}
}
You initialize animalStats with the same objects. So, dog and cat keep share one set of properties.
You should create own properties for every object:
for(int i = 0; i < animals.Count(); i++) {
AnimalInfo vitalStats = new AnimalInfo("vital statistics", new string[] { "name", "sex", "species", "breed", "age" }); //name, species, breed, sex, age.
AnimalInfo veterinarian = new AnimalInfo("veterinarian", new string[] { "Vet Name", "Name of Vet's Practice" });
List<AnimalInfo> animalStats = new List<AnimalInfo> {vitalStats, veterinarian };
animals[i].initializeAnimalInfo(animalStats);
}

Categories

Resources