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);
}
Related
My goal is:
I make a call to the DB which returns to me the list of all my events.
I make a second call to the db which returns to me the list of all my sub-events.
I have an EventViewModel class that contains a List <_EventsLines> class and a List <_SubEventsLines> class.
I need to send the result of these 2 query in a single view but i dont know how could i do that!
I connect to a DB Filemaker and it is based on a single view, that's why I have to make 2 calls.
But then I would like to put the results of these 2 calls in the same object (oEventViewModel) in order to send them back to my view.
Would you have a solution?
Controller
[Authorize]
[HttpGet]
public async Task<ActionResult> Index()
{
ViewBag.sessionv = HttpContext.Session.GetInt32("idMember");
FileMakerRestClient client = new FileMakerRestClient(serverName, fileName, userName, password);
var toFind = new Models.EventsLines { Zkf_CTC = 1053 };
var results = await client.FindAsync(toFind);
Models.EventViewModel oEventViewModel = new Models.EventViewModel
{
_EventsLines = (from o in results select o).ToList()
};
var xtoFind = new Models.SubEventsLines { Zkf_CTC = 1053 };
var xresults = await client.FindAsync(xtoFind);
Models.EventViewModel oSubEventViewModel = new Models.EventViewModel
{
_SubEventsLines = (from x in xresults select x).ToList()
};
ViewBag.Zkf_CTC = 1053;
ViewBag.JsonList = oEventViewModel;
return View(oEventViewModel);
}
Model
public class EventViewModel
{
public List<EventsLines> _EventsLines { get; set; }
public List<SubEventsLines> _SubEventsLines { get; set; }
}
Hi I am writing unit test cases for the following method in my controller.
[HttpGet]
[Route("GetList")]
public IHttpActionResult GetAllMasterList()
{
var MasterList = _masterListRepo.GetAll().Select(t => new { t.MASTER_ID, t.MASTER_NAME }).OrderBy(t=>t.MASTER_NAME).ToList();
return Ok(MasterList);
}
For the above method the unit test case method is as follows.
[TestMethod]
public void AllMastersList()
{
//Arrange
var controller = new MastersController();
var actualResults = _masterListRepo.GetAll().ToList();
//Act
var actionResult = controller.GetAllMasterList();
//Assert
Assert.IsTrue(actionResult.GetType().GetGenericTypeDefinition() == typeof(OkNegotiatedContentResult<>));
var contentExpected = actionResult as OkNegotiatedContentResult<IEnumerable<dynamic>>;
Assert.IsNotNull(contentExpected.Content.ToList());
Assert.AreEqual(contentExpected.Content.Count(), actualResults.Count);
}
I am getting contentExpected as null. How do I cast this Ok() result to get the value. How to do it?
I would strongly recommed against returning anonymous objects.
Introduce a model class with will allow you to easily unit test you api calls.
public class Master {
public string Id { get; set;}
public string Name { get; set;}
}
var MasterList = _masterListRepo.GetAll().Select(t => new Master {Id = MASTER_ID, Name = t.MASTER_NAME).OrderBy(t=>t.MASTER_NAME).ToList();
Also you don't have to return an IHttpActionResult from your Method, you can just return an IEnumerable with also makes your test way more readable
var controller = new MastersController();
var actualResults = _masterListRepo.GetAll().ToList();
var resultsFromController = controller.GetAllMasterList(); //This is now an IEnumerable<Master>)
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.
I have an Interface [BindControls] which takes data from GUI and store it into a list „ieis”.
After that, Into another class, which sends this data through WebServices, I want to take this data from „ieis” and put it into required by WS Class fields (bottom is a snippet of code)
This is the interface:
void BindControls(ValidationFrameBindModel<A.B> model)
{
model.Bind(this.mtbxTax, (obj, value) =>
{
var taxa = TConvertor.Convert<double>((string)value, -1);
if (taxa > 0)
{
var ieis = new List<X>();
var iei = new X
{
service = new ServiceInfo
{
id = Constants.SERVICE_TAX
},
amount = tax,
currency = new CurrencyInfo
{
id = Constants.DEFAULT_CURRENCY_ID
}
};
ieis.Add(iei);
}
},"Tax");
}
This is the intermediate property:
//**********
class A
{
public B BasicInfo
{
get;
set;
}
class B
{
public X Tax
{
get;
set;
}
}
}
//***********
This is the class which sends through WS:
void WebServiceExecute(SomeType someParam)
{
//into ‚iai’ i store the data which comes from interface
var iai = base.Params.FetchOrDefault<A>( INFO, null);
var convertedObj = new IWEI();
//...
var lx = new List<X>();
//1st WAY: I tried to put all data from ‚Tax’into my local list ‚lx’
//lx.Add(iai.BasicInfo.Tax); - this way is not working
//2nd WAY: I tried to put data separately into ‚lx’
var iei = new X
{
service = new ServiceInfo
{
id = iai.BasicInfo.Tax.service.id
},
amount = iai.BasicInfo.Tax.amount,
currency = new CurrencyInfo
{
id = iai.BasicInfo.Tax.currency.id
}
};
lx.Add(iei);
// but also is not working
Can you help me please to suggest how to implement a way that will fine do the work (take data from ‚ieis’ and put her into ‚lx’).
Thank you so much
As noted in my comment, it looks like iai.BasicInfo.Tax is null, once you find out why that is null your original Add() (#1) will work.
So the scenario is this: a user does some action (like earn a badge or unlock something) and an email notification gets sent out. One to the user (with a message like "You've unlocked XYZ...") and then a different message to each of their friends like ("You're friend has unlocked XYZ...").
public interface INotify
{
void Notify(User user, User friend);
}
public class NotificationService
{
private IEnumerable<INotify> _notifiers;
public NotificationService(IEnumerable<INotify> notifiers)
{
_notifiers = notifiers;
}
public SendNotifications()
{
User user = GetUser();
IEnumerable<User> friends = GetFriends();
foreach(var notifier in _notifiers)
{
//Send notification to user
notifier.Notify(user, null);
//send notification to users friends
foreach(var friend in friends)
notifier.Notify(user, friend);
}
}
}
I'm trying to use moq to test that each notifier is called 2x. Once passing null as the second parameter and the second time passing in a value to both parameters.
[Test]
public void MakeSureEveryoneIsNotified()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), null), Times.Once());
notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), It.Is<User>(user => user.UserId == 2)), Times.Once());
}
The problem is that the second verify call throws an ArgumentNullException for the second parameter. Is there away to say "Check the first call has these parameters, and then the second call has other parameters". I know I can get it around it simply by calling:
notifierMock.Verify(x => x.Notify(It.IsAny<User>(), It.IsAny<User>()), Times.Exactly(2));
But I was wanting to be a little more specific. Anyway to do this?
You can achieve this by recording what happens on each call to Notify. Then you can compare the recording to what's expected:
[TestMethod]
public void TestMoqInvocations()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
var invocations = new List<NotifyParams>();
notifierMock
.Setup(f => f.Notify(It.IsAny<User>(), It.IsAny<User>()))
.Callback<string, string>((user, friend) => invocations.Add(new NotifyParams{user = user, friend = friend}));
Assert.AreEqual(1, invocations[0].user.UserId);
Assert.IsNull(invocations[0].friend);
Assert.AreEqual(1, invocations[1].user.UserId);
Assert.AreEqual(2, invocations[1].user.UserId);
}
public struct NotifyParams {
public User user {get;set;}
public User friend { get; set; }
}
You can create a method for get User list. Then get user by It.Is method.
private bool GetUser(User user, List<User> users)
{
if (user != null)
users.Add(user);
return true;
}
[Test]
public void MakeSureEveryoneIsNotified()
{
var notifierMock = new Mock<INotifier>();
var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });
svc.SendNotifications();
var users = new List<User>();
var friends = new List<User>();
// verify how many times call the method
notifierMock
.Verify(x => x.Notify(
It.Is<User>(u => GetUser(u, users)),
It.Is<User>(f => GetFriend(f, friends))
), Times.Exactly(2));
Assert.AreEquals(2, users.Count);
Assert.AreEquals(1, users[0].UserId);
Assert.AreEquals(1, users[1].UserId);
Assert.AreEquals(1, friends.Count);
Assert.AreEquals(2, friends[0].UserId);
}