Mock method of system-under-test with Moq - c#

I have the following three methods in the CompanyApplication class (along with the supporting factories and services listed):
public ResultSet<CompanyDto> AddCompany(CompanyDto companyDto)
{
var result = new CompanyDto();
var company = new Company();
Mapper.Map(companyDto, company);
using (ITransaction t = _transactionFactory.Create())
{
company = _companyService.Add(company);
t.Commit();
}
Mapper.Map(company, result);
return new ResultSet<CompanyDto>(1, new[] { result });
}
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto)
{
var result = new CompanyContactDto();
var company = new Company();
var contact = new CompanyContact();
Mapper.Map(companyContactDto, contact);
using (ITransaction t = _transactionFactory.Create())
{
var contactCompanies = FindByIdJoin<Company, CompanyDto>(companyContactDto.CompanySK);
Mapper.Map(contactCompanies.Data.First(), company);
company.CompanyContacts.Add(contact);
company = _companyService.Update(company);
t.Commit();
}
Mapper.Map(contact, result);
return new ResultSet<CompanyContactDto>(1, new[] { result });
}
public ResultSet<T_DtoType> FindByIdJoin<T_DbType, T_DtoType>(long id)
{
IAbstractRepository<T_DbType> repository = EnsureRepository<T_DbType>();
T_DbType entity = repository.FindByIdJoin(id);
return (entity == null ? null : MapResultSetToDto<T_DbType, T_DtoType>(entity));
}
There are other objects in play here, which is why the FindByIdJoin has been made a separate method in the CompanyApplication class.
I have set up the testing class with some mocks and an instance of the CompanyApplication class:
private Mock<ICompanyRepository> _mockCompanyRepository;
private Mock<ICompanyDomain> _mockCompanyService;
private Mock<ITransactionFactory> _mockTransactionFactory;
private Mock<ITransaction> _mockTransaction;
private CompanyApplication _companyApplication;
[Setup]
public void SetUp()
{
_mockCompanyRepository = new Mock<ICompanyRepository>(MockBehavior.Strict);
_mockCompanyService = new Mock<ICompanyDomain>(MockBehavior.Strict);
_mockTransactionFactory = new Mock<ITransactionFactory>(MockBehavior.Strict);
_mockTransaction = new Mock<ITransaction>(MockBehavior.Strict);
_companyApplication = new CompanyApplication(
_mockCompanyRepository.Object,
_mockCompanyService.Object,
_mockTransactionFactory.Object);
}
I am successfully able to test the FindByIdJoin and AddCompany methods directly in Moq like this:
[Test]
public void CanFindCompanyByIdJoin()
{
var data = new Company {ObjectId = 1, Name = "Company1"};
_mockCompanyRepository.Setup(x => x.FindByIdJoin(It.Is<long>(arg => arg == data.ObjectId)))
.Returns(data);
var result = _companyApplication.FindByIdJoin<Company, CompanyDto>(data.ObjectId);
Assert.AreEqual(data.ObjectId, result.Data.First().ObjectId);
}
[Test]
public void CanAddCompany()
{
var data = new Company {ObjectId = 1, Name = "Company1"};
_mockCompanyService.Setup(x => x.Add(It.Is<Company>(arg => arg.ObjectId == data.ObjectId)))
.Returns(data);
_mockTransactionFactory.Setup(x => x.Create()).Returns(_mockTransaction.Object);
_mockTransaction.Setup(x => x.Commit());
_mockTransaction.Setup(x => x.Dispose());
var dto = new CompanyDto {ObjectId = 1, Name = "Company1"};
var result = _companyApplication.AddCompany(dto);
_mockCompanyService.Verify(t => t.Add(It.IsAny<Company>()));
}
Those two tests pass just fine. However, I'm having trouble coming up with a test for AddCompanyContact, because it calls FindByIdJoin as part of its flow, and that seems to be getting in the way.
Specifically, is there a way to mock var contactCompanies = FindByIdJoin<Company, CompanyDto>(companyContactDto.CompanySK) in a test for the AddCompanyContact method?
Thanks!

There is two alternatives that i see depending on the amount of work that you want to do.
Wrap that call into a object and instantiate it using a IOC container. This is the one that i feel would take the most effort if you are not using one already.
Turn that call into a Func and make a method without that parameter that does the call. This approach has the disadvantage that the top call will be untestable but will allow access to the rest of the method.
Example Below:
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto)
{
AddCompanyContact(CompanyContactDto, ()=>
{
return FindByIdJoin<Company, CompanyDto> companyContactDto.CompanySK);
}
}
public ResultSet<CompanyContactDto> AddCompanyContact(CompanyContactDto companyContactDto, Func<WhateverTheMethodReturns> findIdReplacement)
{
var result = new CompanyContactDto();
var company = new Company();
var contact = new CompanyContact();
Mapper.Map(companyContactDto, contact);
using (ITransaction t = _transactionFactory.Create())
{
var contactCompanies = findIdReplacement();
Mapper.Map(contactCompanies.Data.First(), company);
company.CompanyContacts.Add(contact);
company = _companyService.Update(company);
t.Commit();
}
Mapper.Map(contact, result);
return new ResultSet<CompanyContactDto>(1, new[] { result });
}

I was over complicating the problem... since AddCompanyContact calls FindByIdJoin, all I needed to do was mock the same interface that is used in FindByIdJoin.
Lesson learned: mock interfaces, not classes.

Related

Mocking Microsoft Graph API with in memory data

I am trying to unit test a method that returns a list of users with mocking by creating a list of users and passing them in to mock whether my repository methods returns that list of users.
At the moment I am getting an empty list. I am wondering if there's something missing when passing in the users in the test method.
I have a repository class with a method called GetUsersOnly() which makes a call to the Graph API like this:
this.graphApi.GetUsersAsync().Result;
This GetUsersAsync() is inside of the GraphAPI class that I wrote and makes a call to the Microsoft Graph API to get a list of users.
public Task<IGraphServiceUsersCollectionPage> GetUsersAsync()
{
return this.appClient.Users
.Request(this.queryOptions)
.Select(#$"
Id,
DisplayName,
GivenName,
Surname,
Mail,
OtherMails,
CompanyName,"
.OrderBy("DisplayName")
.GetAsync();
}
public class B2CRepository : IB2CRepository
{
private readonly IGraphAPI graphApi;
public B2CRepository(IGraphAPI graphApi)
{
this.graphApi = graphApi;
}
private List<User> GetUsersOnly()
{
var request = this.graphApi.GetUsersAsync().Result;
List<User> users = new List<User>();
var graphUsers = request.ToList();
do
{
users.AddRange(graphUsers);
var nextPage = request.NextPageRequest;
graphUsers = nextPage?.GetAsync().Result.ToList() ?? new List<User>();
}
while (graphUsers.Count > 0);
return users;
}
}
Inside my test I am mocking the GraphAPI class:
var mockGraphAPI = new Mock<IGraphAPI>();
Test method looks like this: my goal is simply to pass in some list of users and return that list from my repo method GetUsersOnly();
[TestMethod]
public void GetUserTest()
{
var users = new List<User>();
var mockGraphAPI = new Mock<IGraphAPI>();
for (int i = 0; i < 3; i++)
{
var user = new User()
{
DisplayName = "TestUser2" + i,
};
users.Add(user);
}
var mockUserPageResult = new Mock<IGraphServiceUsersCollectionPage>();
mockGraphAPI.Setup(api =>
api.GetUsersAsync()).ReturnsAsync(mockUserPageResult.Object);
mockUserPageResult.SetupGet(page => page.NextPageRequest);
this.b2CRepository = new B2CRepository(mockGraphAPI.Object);
var usersResult = this.b2CRepository.GetUsers();
Assert.IsTrue(usersResult.Count() == 2);
}

FakeItEasy to mock an object-modifying method

I am trying to write a unit test for a method that relies on a dependency which offers a method that accepts an object and modifies it, but does not return it on a "new path", e.g. as a return value or on a by reference parameter.
public class Product
{
public string Name { get; set; }
}
public interface IFixer
{
void Modify(Product product);
}
public class Fixer: IFixer
{
public void Modify(Product product)
{
if (string.IsNullOrEmpty(product.Name))
{
product.Name = "Default";
}
}
}
public class Manager()
{
private readonly IFixer _fixer;
public Manager(IFixer fixer)
{
_fixer = fixer;
}
public bool IsProductNew(int id)
{
var product = GetProduct(id); // Gets an object instance from a repository, e.g. a file or a database, so we can have something to operate on.
_fixer.Modify(product);
return product.Name != "Default";
}
}
So I want to be able to test my Manager class' IsProductNew() method:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var isNew = manager.IsProductNew(A<int>._);
Assert.True(isNew);
What I am missing here is: How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
Answering this effectively is dependent on the definition of GetProduct(id);
If however the IFixer implementation has no knock on effects or undesirable behavior then there really is no need to mock it.
//Arrange
var fixer = new Fixer();
var manager = new Manager(fixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
But to answer
How do I mock the behaviour of IFixer.Modify(), i.e. have it modify a Product object instance?
you would need a callback that captures the matched parameter
//Arrange
var fakeFixer = A.Fake<IFixer>();
A.CallTo(() => fakeFixer.Modify(A<Product>._))
.Invokes((Product arg) => arg.Name = "Not Default Name");
var manager = new Manager(fakeFixer);
//Act
var isNew = manager.IsProductNew(1);
//Assert
Assert.True(isNew);
Reference Invoking Custom Code
So I want to be able to test my Manager class' IsProductNew() method
You cannot test it effectively in its current form. You will not get 100% coverage. You should either:
pass the product directly:
public bool IsProductNew(Product product)
{
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer);
var product = new Product { Id = 100, Name = "Default" }; // create another test for where Name != "Default"
var isNew = manager.IsProductNew(product);
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
or, pass a "product getter" into the Manager() constructor:
public Manager(IFixer fixer, IProductGetter productGetter)
{
_fixer = fixer;
_productGetter = productGetter;
}
...
public bool IsProductNew(int id)
{
var product = _productGetter.GetProduct(id);
_fixer.Modify(product);
return product.Name != "Default";
}
which you can test by:
var fakeProductGetter = A.Fake<IProductGetter>();
// Prime the product getter to return a product
A.CallTo(() => fakeProductGetter.Get(A<int>.Ignored))
.Returns(new Product{
Id = 100,
Name = "Default" // create another test for where Name != "Default"
});
var fakeFixer = A.Fake<IFixer>();
var manager = new Manager(fakeFixer, fakeproductGetter);
var isNew = manager.IsProductNew(100);
// Assert that a call is made to productGetter.Get with the ID
A.CallTo(() => productGetter.Get(100)).MustHaveHapennedOnceExactly();
// Assert that fixer.modify is called with the product
A.CallTo(() => fakeFixer.Modify(A<product>.That.Matches(p => p.Id == 100))).ShouldHaveBeenCalledOnceExactly();
// Should return false because of product name = "Default"
Assert.IsFalse(isNew);
The choice you make depends on whether you want the IsProductNew() method to be responsible for getting the product by the ID, or if you want to just pass the product directly.

How to add annotation to an entity?

I am attempting to write a unit test for this method:
public List<Annotation> GetNotesByOrderGuid(Guid orderGuid)
{
var result = _xrmServiceContext.SalesOrderSet.Where(x => x.Id == orderGuid); //!!!!! this is returning correctly 1 record, however, it shows NULL for the list of annotations
//do some stuff and return a list of annotations
}
My unit test creates 2 notes, and attaches them to the sales order:
private XrmFakedContext _fakeContext;
[NotNull]
private IOrganizationService _fakeOrganizationService;
[Test]
public void GetNotesByOrderGuid_ExistingRecordHavingNotes_ReturnsListOfThoseNotes()
{
using (var xrmServiceContext = new XrmServiceContext(_fakeOrganizationService))
{
// Arrange
var salesOrderGuid = Guid.NewGuid();
var salesOrder = new SalesOrder { Id = salesOrderGuid };
var note1 = new Annotation
{
Id = Guid.NewGuid(),
NoteText = "this is note1",
ObjectId = new EntityReference(SalesOrder.EntityLogicalName, salesOrderGuid),
ObjectTypeCode = salesOrder.LogicalName
};
var note2 = new Annotation
{
Id = Guid.NewGuid(),
NoteText = "this is note2",
ObjectId = new EntityReference(SalesOrder.EntityLogicalName, salesOrderGuid),
ObjectTypeCode = salesOrder.LogicalName
};
_fakeContext.Initialize(new List<Entity> { salesOrder, note1, note2});
var sut = new SalesOrderService(xrmServiceContext);
// Act
// Assert
Assert.That(sut.GetNotesByOrderGuid(salesOrderGuid), Is.InstanceOf<List<Annotation>>());
}
}
[SetUp]
public void Init()
{
_fakeContext = new XrmFakedContext { ProxyTypesAssembly = Assembly.GetAssembly(typeof(SalesOrder)) };
_fakeOrganizationService = _fakeContext.GetFakedOrganizationService();
}
What am doing incorrectly in adding annotations to my entity?
The reason I ask is because when the unit tests runs this code:
var result = _xrmServiceContext.SalesOrderSet.Where(x => x.Id == orderGuid);
it shows that although there is 1 result, as there correctly should be; it shows that no annotations have been linked to it:

mocking a method with an anonymous type argument

I have the following code:
var connector = new Mock<IConector>();
connector
.Setup(cn => cn.listar("FetchEstandar", new Estandar(), new {Id = 1}))
.Returns(new List<Estandar>{ new Estandar {Id = 1} });
var entidad = connector.Object
.listar("FetchEstandar", new Estandar(), new {Id = 1});
when I call listar on the connector Object, I get an "Expression Cannot Contain an Anonymouse Type" error. I've tried with rhino mocks and moq.
Is there any way I can mock this method? am I doing something wrong? alternatively, I could ignore this parameter but I don't know how. I really just need to test the value of the first parameter and ignorearguments works but I have no idea whether or how I can get this value if I use it
I do not know if this is the only way to match an anonymous object but it can be done using It.Is<>() and reflection
public class Estandar {
public int Id { get; set; }
}
public interface IConector {
IEnumerable<Estandar> listar(string name, Estandar estandar, object key);
}
[TestMethod]
public void CheckAnonymous() {
var connector = new Mock<IConector>();
connector.Setup(cn => cn.listar("FetchEstandar",
It.IsAny<Estandar>(),
It.Is<object>(it => MatchKey(it, 1))))
.Returns(new List<Estandar> { new Estandar { Id = 1 } });
var entidad = connector.Object.listar("FetchEstandar", new Estandar(), new { Id = 1 });
Assert.AreEqual(1, entidad.Count());
}
public static bool MatchKey(object key, int soughtId) {
var ret = false;
var prop = key.GetType().GetProperty("Id");
if (prop != null) {
var id = (int)prop.GetValue(key, null);
ret = id == soughtId;
}
return ret;
}

How to use Moq to satisfy a MEF import dependency for unit testing?

This is my interface
public interface IWork
{
string GetIdentifierForItem(Information information);
}
and my class
public class A : IWork
{
[ImportMany]
public IEnumerable<Lazy<IWindowType, IWindowTypeInfo>> WindowTypes { get; set; }
public string GetIdentifierForItem(Information information)
{
string identifier = null;
string name = information.TargetName;
// Iterating through the Windowtypes
// searching the 'Name' and then return its ID
foreach (var windowType in WindowTypes)
{
if (name == windowType.Metadata.Name)
{
identifier = windowType.Metadata.UniqueID;
break;
}
}
return identifier;
}
}
Problem : I want to unit test the method GetIdentifierForItem
Here is what I tried doing to solve it -
(1)Create a mock Lazy and set the values that it needs to return on property gets
var windowMock = new Mock<Lazy<IWindowType, IWindowTypeInfo>>();
windowMock.Setup(foo => foo.Metadata.Name).Returns("Data");
windowMock.Setup(foo => foo.Metadata.UniqueID).Returns("someString");
(2)Create a window type list and the above mocked object and then set it to the created A object
var WindowTypesList = new List<IWindowType, IWindowTypeInfo>>();
WindowTypesList.Add(windowMock.Object);
A a = new A();
a.WindowTypes = WindowTypesList;
(3) Create the information mock
var InfoMock = new Mock<Information>();
InfoMock.Setup(foo => foo.TargetName).Returns("Data");
To put all of the above together as the unit test
[TestMethod]
public void GetIDTest()
{
var windowMock = new Mock<Lazy<IWindowType, IWindowTypeInfo>>();
windowMock.Setup(foo => foo.Metadata.Name).Returns("Data");
windowMock.Setup(foo => foo.Metadata.UniqueID).Returns("someString");
var WindowTypesList = new List<Lazy<IWindowType, IWindowTypeInfo>>();
WindowTypesList.Add(windowMock.Object);
A a = new A();
a.WindowTypes = WindowTypesList;
var InfoMock = new Mock<Information>();
InfoMock.Setup(foo => foo.TargetName).Returns("Data");
string expected = "someString"; // TODO: Initialize to an appropriate value
string actual;
actual = a.GetIdentifierForItem(InfoMock.Object);
Assert.AreEqual(expected, actual);
}
This unit test fails to execute and throws an exception 'TargetInvocationException' and veiwing the detail, it looks like I am doing something that I should not be doing.
But I am not sure how do it other way. I have read some of the links in the Quickstart guide of Moq. I know I am missing something. Can you help me by guiding how to unit test this?
This is how it may be done, after setting up the mocks
1) Creating a CompositionContainer, that holds the imports.
2) Adding Mocks to the container.
container.ComposeExportedValue(mock.Object);
3) Create an instance of tested class
4) Compose mocks to the import
container.ComposeParts(instance);
You don't need to Mock the Lazy<T,TMetadta>. It is flexible enough to work with your test. Instead, Mock the IWindowTypeInfo
[TestMethod]
public void GetIDTest()
{
var windowTypeInfoMock = new Mock<IWindowTypeInfo>();
windowTypeInfoMock.Setup(foo => foo.Name).Returns("Data");
windowTypeInfoMock.Setup(foo => foo.UniqueID).Returns("someString");
var lazyWindow =
new Lazy<IWindowType, IWindowTypeInfo>(windowTypeInfoMock.Object);
var WindowTypesList = new List<Lazy<IWindowType, IWindowTypeInfo>>();
WindowTypesList.Add(lazyWindow);
var a = new A();
a.WindowTypes = WindowTypesList;
var InfoMock = new Mock<Information>();
InfoMock.Setup(foo => foo.TargetName).Returns("Data");
string expected = "someString";
string actual;
actual = a.GetIdentifierForItem(InfoMock.Object);
Assert.AreEqual(expected, actual);
}
Your test passes on my machine with only small modifications, you do not need to use a composition container for this test.

Categories

Resources