Faking the find method in FakeDbSet implementation - c#

I want to unit test a controller that takes a FormCollection and has the Find method. I have successfully implemented a fake DbContext and a FakeDbSet (from here) so that I can use the fake objects in my tests.
The specific method I want to test looks like this:
//
// POST: /Order/SettleOrders
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SettleOrders(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var ordersCollection = new List<Order>();
// Get values of form
var OrderIdArray = c.GetValues("item.OrderId");
var UnitPriceArray = c.GetValues("item.UnitPrice");
for (i = 0; i < OrderIdArray.Count(); i++)
{
// Find order in database and update the unitprice and isconfirmed status
Order order = db.Orders.Find(Convert.ToInt32(OrderIdArray[i]));
order.UnitPrice = Convert.ToDecimal(UnitPriceArray[i]);
order.IsConfirmed = true;
db.SetModified(order);
ordersCollection.Add(order);
}
db.SaveChanges();
}
// Return orders of this date to view
var currentDate = DateTime.Today;
var orders = db.Orders.Include(o => o.Product)
.Include(o => o.User)
.Where(o => o.Date == currentDate);
return View("Confirmation", orders.ToList().OrderBy(o => o.User.Name));
}
This is how I set up the test of my OrderController using Moq:
[TestInitialize]
public void OrderControllerTestInitialize()
{
// Arrange
var unconfirmedMemoryItems = new FakeOrderSet
{
// #TODO Tests/methods should ideally not be dependent on DateTime.Today...
new Order { OrderId = 1, UnitPrice = 1.00M, Quantity = 2, Date = DateTime.Today, IsConfirmed = false },
new Order { OrderId = 2, UnitPrice = 2.00M, Quantity = 1, Date = DateTime.Today, IsConfirmed = false }
};
// Create mock unit of work
var unconfirmedMockData = new Mock<ISeashellBrawlContext>();
unconfirmedMockData.Setup(m => m.Orders).Returns(confirmedMemoryItems);
// Setup controller
unconfirmedOrderController = new OrderController(confirmedMockData.Object);
}
Then the test goes likes this to confirm the unconfirmed orders are becoming confirmed.
[TestMethod]
public void TestSettleOrdersPost()
{
// Invoke
FormCollection form = CreatesettleOrdersPostFormCollection();
var viewResult = unconfirmedOrderController.SettleOrders(form) as ViewResult;
var ordersFromView = (IEnumerable<Order>)viewResult.Model;
// Assert
Assert.AreEqual(3, ordersFromView.ElementAt(0).Quantity,
"New item should be added to older one since it has same index and is of same date");
Assert.AreEqual(true, ordersFromView.ElementAt(0).IsConfirmed,
"The item should also be set to confirmed");
}
// Helper methods
private static FormCollection CreatesettleOrdersPostFormCollection()
{
FormCollection form = new FormCollection();
form.Add("item.OrderId", "1");
form.Add("item.UnitPrice", "2.00");
form.Add("item.OrderId", "2");
form.Add("item.UnitPrice", "3.00");
return form;
}
Unfortunately I get the following error message:
Test Name: TestSettleOrdersPost
Result Message:
System.NullReferenceException: Object reference not set to an instance
of an object. Result StackTrace: at
Controllers.OrderController.SettleOrders(FormCollection c) in
Controllers\OrderController.cs:line 121
This probably has to do with the fake Find method not doing what it is supposed to do. The find method I use looks like this:
class FakeOrderSet : FakeDbSet<Order>
{
public override Order Find(params object[] keyValues)
{
var id = Convert.ToInt32(keyValues[0]);
Order o = null;
IQueryable<Order> keyQuery = this.AsQueryable<Order>();
foreach (var order in keyQuery)
{
if (order.OrderId == id)
{
o = order;
}
}
return o;
}
}
I have no idea how to improve this code. Looking at it I am convinced it should work. Since I am a 7-day noob to unit testing this conviction is of not much worth though. I hope someone can help me out.

I think you can include Find method implementation in your generic FakeDbSet<T> class.
For example if all your entites have property Id that is mapped to primary key in database you can do following:
public class FakeDbSet<T>
{
....
public T Find(params object[] keyvalues)
{
var keyProperty = typeof(T).GetProperty(
"Id",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
var result = this.SingleOrDefault(obj =>
keyProperty.GetValue(obj).ToString() == keyValues.First().ToString());
return result;
}
}
If your key property is not Id you can try to determine some algorith how to recognize key property for the entity via reflection (for example if Order class have OrderId key property you can try to determine it by getting class name with reflection and concatenating it with "Id" string).

I have the same problem:
public override TEntity Find(params object[] keyValues)
{
if (keyValues.Length == 0)
throw new ArgumentNullException("keyValues");
return this.SingleOrDefault(GenerateKeyFilter(keyValues));
}
private Expression<Func<TEntity, bool>> GenerateKeyFilter(object[] keyValues)
{
var conditions = new List<BinaryExpression>();
var objectParam = Expression.Parameter(typeof(TEntity));
var keyFields = !!!Helper.KeyFields<TEntity>();
if (keyFields.Count != keyValues.Length)
throw new KeyNotFoundException();
for (var c = 0; c < keyFields.Count; c++)
conditions.Add(Expression.MakeBinary(
ExpressionType.Equal,
Expression.MakeMemberAccess(objectParam, keyFields[c]),
Expression.Constant(keyValues[c], keyFields[c].PropertyType)
));
var result = conditions[0];
for (var n = 1; n < conditions.Count; n++)
result = Expression.And(result, conditions[n]);
return Expression.Lambda<Func<TEntity, bool>>(result, objectParam);
}
This works well, however, to create the tests I had to reconfigure the models and manually set the keys, similar to use of EntityTypeConfiguration.

Related

How to implement IConvertible

I have some test code to check if 2 sides are equal.
public void GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos()
{
// Arrange
var companyRequset = new CompanyRequest();
// Act
var companyDtos = _datlinqServiceMock.GetCompanies(companyRequset);
// Assert
Assert.IsTrue(companyDtos != null && companyDtos.Any());
Assert.AreEqual(DatlinqServiceMock.CompanyName, companyDtos.FirstOrDefault().Name);
}
That calls this.
public class DatlinqServiceMock: DatlinqService
{
public static string CompanyName = "Company_Test";
public override T GetApi<Q,T>(string apiMethod, Q request)
{
var companyList = new List<Company>()
{
new Company(){ Name = CompanyName}
};
return (T)Convert.ChangeType(companyList, typeof(T));
}
}
GetCompanies:
public List<Company> GetCompanies(CompanyRequest request)
{
if (request == null)
{
return new List<Company>();
}
var searchCompany = new SearchCompanyRequest();
searchCompany.Query = request.Name;
searchCompany.DatlinqKey = ConfigurationManager.AppSettings["Datlinq_Key"];
var searchCompanyResponse = GetApi<SearchCompanyRequest,SearchCompanyResponse>(DatlinqApiMethod.SearchCompany, searchCompany);
var companies = searchCompanyResponse.Result
.Select(c => new Company { Id = c.Id, Name = c.Name })
.ToList();
return companies;
}
GetApi:
public virtual T GetApi<Q,T>(string apiMethod, Q request)
{
var result = default(T);
try
{
var url = String.Format("{0}{1}", _apiUrl, apiMethod);
if (request != null)
{
url = QueryHelpers.AddQueryString(url, request.ToDictionary());
}
var apiResponse = _httpClient.GetAsync(url).Result;
if (apiResponse.IsSuccessStatusCode)
{
string apiResponseString = apiResponse.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(apiResponseString))
{
result = JsonConvert.DeserializeObject<T>(apiResponseString);
}
}
}
catch (Exception)
{
// do something
}
return result;
}
And I get an error when I execute the first test
Message: 
Test method Lavazza.ContractTool.Datlinq.Tests.Services.DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos threw exception:
System.InvalidCastException: Object must implement IConvertible.
Stack Trace: 
Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
Convert.ChangeType(Object value, Type conversionType)
DatlinqServiceMock.GetApi[Q,T](String apiMethod, Q request) line 79
DatlinqService.GetCompanies(CompanyRequest request) line 23
DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos() line 32
I hope this is enough code to know what the problem/solution is if not let me know what you need.
To answer some question asked below.
Dai: I am trying to find what this is and why I need it because it came up in the error but the microsoft docs don't make it clear for me.
Jeroen: It is kind of a legacy project so I can't/won't add extra dependencies.
The "issue" here is that your GetApi method is designed to return a sort of generic response - in this specific case SearchCompanyResponse - but you're trying to override it to return a List<Company> which is wrong because that is what your GetCompanies method does (ie turn a SearchCompanyResponse to a List<Company>).
Suffice it to say this has nothing to do with implementing IConvertable.
What you would be better off doing is serializing a SearchCommpanyResponse that you wish to use for testing to a file, and using that file-based response for your testing.
That way your overridden "Mock" would be
public override T GetApi<Q,T>(string apiMethod, Q request)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText("mytestfile.json"));
}

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 unit test method that uses DbContext.Database.SqlQuery<T>

I have written a method that gets data from the database using DbContext.Database.SqlQuery() (EF6.1):
internal List<WorkOrderLine> Get()
{
var sql = GetSql();
var workOrders = Context.Database.SqlQuery<Model.Analysis.WorkOrder>(sql).ToList();
return workOrders.Select(workOrder => new WorkOrderLine
{
Id = workOrder.a,
Title = workOrder.b,
Status = workOrder.c,
Location = workOrder.d,
AssignedTo = workOrder.e,
StartDate = workOrder.f,
DueDate = workOrder.g,
CompletedDate = h
}).ToList();
}
I want to write a unit test for the method and check that the expected SQL is passed into SQLQuery and then to pass back a list of data so that it can be processed via the rest of the method so that I can check the output.
I believe the correct/best approach would be to mock the DbContext and pass this mocked context into the class instead of a real context. If so, I think I might be able to do this with one of the following:
Use Moq
Manually create a mock to carry out the tests and return the data
Is using mocks the correct technique?
If so, which of these 2 options is the simplest/best?
P.S. I usually use Effort when testing with EF but it doesn't handle this method.
EDIT:
Here is the complete class:
internal Report(MyContext context, ChartWidgetFilter filters, string ownerEntityFilter)
: base(context, filters, ownerEntityFilter)
{
}
internal List<WorkOrderLine> Get()
{
var sql = GetSql();
var workOrders = Context.Database.SqlQuery<Model.Analysis.WorkOrder>(sql).ToList();
return workOrders.Select(workOrder => new WorkOrderLine
{
Id = workOrder.a,
Title = workOrder.b,
Status = workOrder.c,
Location = workOrder.d,
AssignedTo = workOrder.e,
StartDate = workOrder.f,
DueDate = workOrder.g,
CompletedDate = h
}).ToList();
}
private string GetSql()
{
//return the sql generated using the filters and ownerEntityFilter
//parameters passed into the constructor
}
}
EDIT 2:
The two things that I need to test are that:
GetSql() creates the correct SQL for the parameters passed into the constructor - ChartWidgetFilter filters, string ownerEntityFilter
That the return workOrders.Select... statement returns a correctly mapped list of WorkOrderLine objects for a list of Model.Analysis.WorkOrder objects
Here is a example about how to "mock" for a unit test
public class SolvencyBllTest
{
private MyAttBLL myAttBll;
private readonly List<AttestationEntity> attestationsFakeForTest = new List<AttestationEntity>
{
/// ... Build the child object , used for 'mock'
}
//Initialize event => here we define what the 'mock' should to de when we use the [GetListWithChildren] function
[TestInitialize]
public void Setup()
{
var mockedAttestationFakeToTest = new Mock<IAttestationDataAccessLayer>();
//setup GetAll : return the whole list
mockedAttestationFakeToTest
.Setup(attestation => attestation.GetListWithChildren(It.IsAny<Expression<Func<AttestationEntity, bool>>>()))
.Returns((Expression<Func<AttestationEntity, bool>> expression) =>
{
return this.attestationsFakeForTest.AsQueryable().Where(expression);
});
this.myAttBll = new MyAttBLL(attestationsCertificatesRefundDal: null, attestationDal: mockedAttestationFakeToTest.Object, emailNotifier: mockedEmailNotifier.Object);
}
[TestMethod]
public void SolvencyBllTest_CheckAttestation()
{
// Initalize the result
SolvencyCheckResult solvencyCheckResult = new SolvencyCheckResult()
{
solvency = new SolvencyModel()
};
// Declare and initializes our object which encapsulates our parameters for the solvency check
SolvencyCheckParameters solvencyCheckParams = new SolvencyCheckParameters(TestConstants.Contact.LAST_NAME, TestConstants.Contact.FIRST_NAME, TestConstants.Contact.BIRTH_DATE, TestConstants.Address.STREET, TestConstants.Address.ZIPCODE, TestConstants.UNIT_TEST_USER);
// this (solvencyBll) will not try to find in the database but in the collection with just mock before
// Try to retrieve all certificates dating back 3 months and have the same name + first name + date of birth
List<AttestationModel> attsLatestToCheck = this.myAttBll.CheckLatestAttestation(solvencyCheckResult, solvencyCheckParams);
// 1 attestation created today => OK
// 1 attestation created 1 month ago => OK
// 1 attestation created 2 month ago => OK
// 1 attestation created 4 month ago => KO
Assert.AreEqual(3, attsLatestToCheck.Count);
}
Example for use the dbContext from the BLL part functions
public IEnumerable<AttestationEntity> GetListWithChildren(Expression<Func<AttestationEntity, bool>> pred)
{
using (ScDbContext context = new ScDbContext())
{
return this.GetListWithChildrenInternal(context, pred).OrderBy(att => att.CreatedDate).ToList();
}
}
internal IEnumerable<AttestationEntity> GetListWithChildrenInternal(ScDbContext context, Expression<Func<AttestationEntity, bool>> pred)
{
return this.GetListInternal(context, pred, attestationChildren).OrderBy(att => att.CreatedDate).ToList();
}
internal IEnumerable<E> GetListInternal(DBC context, Expression<Func<E, bool>> where, params Expression<Func<E, object>>[] navigationProperties)
{
IQueryable<E> dbQuery = context.Set<E>();
//Apply eager loading
foreach (Expression<Func<E, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<E, object>(navigationProperty);
return dbQuery
//.AsNoTracking() //Don't track any changes for the selected item
.Where(where)
.ToList(); //Apply where clause
}

Unit Test Mocking an IHttpActionResult GetId method

I am creating some unit tests for a controller I have however I ran into a problem.
Basically I have the following:-
The Controller Method :-
[ResponseType(typeof(Attrib))]
public IHttpActionResult GetAttrib(int id)
{
var attrib = _attribsRepository.GetAttrib(id);
if (attrib == null)
{
return NotFound();
}
return Ok(attrib);
}
Its a simple Web API 2.0 method.
Then I have the Repository :-
public Attrib GetAttrib(int id)
{
return DbSet.FirstOrDefault(x=>x.Id == id);
}
And finally the Test Method:-
public class AttribsControllerTests
{
public Mock<IAttribsRepository> _attribsRepositoryMock;
public List<Attrib> AttribList;
public AttribsController AttribsController;
[SetUp]
public void Init()
{
_attribsRepositoryMock = new Mock<IAttribsRepository>();
AttribList = new List<Attrib>
{
new Attrib()
{
Id = 1,
AttributeId = "Cro",
AttributeName = "Crossing",
AttributeType = "Tech",
AttributeValue = 1
},
new Attrib()
{
Id = 2,
AttributeId = "Dri",
AttributeName = "Dribbling",
AttributeType = "Tech",
AttributeValue = 2
},
new Attrib()
{
Id = 3,
AttributeId = "Fin",
AttributeName = "Finishing",
AttributeType = "Tech",
AttributeValue = 3
}
};
}
[Test]
public void Get_Check_That_Id1_Returns_Crossing()
{
//Arrange
_attribsRepositoryMock.Setup(t => t.GetStaticAttribs()).Returns(AttribList.AsQueryable());
//Act
var attribsController = new AttribsController(_attribsRepositoryMock.Object);
var result = attribsController.GetAttrib(1) as OkNegotiatedContentResult<Attrib>;
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(AttribList[0].AttributeName, "Cor");
}
}
For some reason, the result is always null, so its not hitting the controller correctly.
Any ideas why this could happen? When debugging, the correct Mock Repository is hitting the controller, and it should have the 3 entries in it.
Any help will be very much appreciated.
You setup GetStaticAttribs but it is used nowhere in the example you showed. You were suppose to setup IAttribsRepository.GetAttrib
Based on your example
[Test]
public void Get_Check_That_Id1_Returns_Crossing() {
//Arrange
var id = 1;
_attribsRepositoryMock.Setup(t => t.GetAttrib(id)).Returns(AttribList[0]);
var attribsController = new AttribsController(_attribsRepositoryMock.Object);
//Act
var result = attribsController.GetAttrib(id) as OkNegotiatedContentResult<Attrib>;
//Assert
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(result.Content.AttributeName, "Crossing");
}

Mock method of system-under-test with Moq

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.

Categories

Resources