Moq an interface and setting up a mock - unit-testing

I have an Interface to check vowel and to return a char as
public interface IVowChecker
{
bool VowCheck(char a);
char ReturnChar(int n);
Student GetStudentById(int n);
}
It's concrete class implementation
public class VowChecker:IVowChecker
{
public bool VowCheck(char a)
{
if (a == 'a' || a == 'A')
return true;
return false;
}
public char ReturnChar(int n)
{
return (char)n;
}
public Student GetStudentById(int n)
{
var list = new []
{
new Student{RollNo=1,Name="A"},
new Student{RollNo=2,Name="B"},
new Student{RollNo=3,Name="C"},
new Student{RollNo=4,Name="D"},
new Student{RollNo=5,Name="E"},
new Student{RollNo=6,Name="F"},
};
var student = from i in list
where i.RollNo == n
select i;
return student.FirstOrDefault();
}
}
And a service using this VowChecker
public class MyCharService
{
private readonly IVowChecker _checker;
public MyCharService(IVowChecker checker)
{
_checker = checker;
}
public bool CheckInput(char a)
{
return _checker.VowCheck(a);
}
public char ReturnChar(int a)
{
return _checker.ReturnChar(a);
}
public Student GetStudentById(int n)
{
return _checker.GetStudentById(n);
}
}
I am using Xunit testing framework for unit testing and Moq library.
My unit test code is
public class MyCharServiceShould
{
...
[Theory]
[InlineData(65)]
[InlineData(68)]
public void BeAbleToReturnChar(int n)
{
var service = new Mock<IVowChecker>();
service.Setup(i => i.ReturnChar(n)).Returns('A');
var obj = new MyCharService(service.Object);
var result = obj.ReturnChar(n);
}
[Theory]
[InlineData(2)]
public void BeAbleToRetrieveStudent(int n)
{
var service = new Mock<IVowChecker>();
service.Setup<Student>(i => i.GetStudentById(n)).Returns<Student>(f => (Student)f);
var ob = new MyCharService(service.Object);
var res = ob.GetStudentById(2);
Assert.Equal(res.Name, "B");
}
}
My Student class
public class Student
{
public int RollNo{ get; set; }
public string Name { get; set; }
}
I have used a debugger in the last line of my test and checked the values of both the tests. For the 1st test I am expecting 'A' as the result and for the 2nd test I am expecting 'D' as the result. But in both the cases I am getting 'A' as the result. Can anyone kindly help me out where I am missing out the concept. Thank you.

The problem is that the setup for ReturnChar
service.Setup(i => i.ReturnChar(n)).Returns('A');
says,
Whenever ReturnChar() is called, give an answer of 'A'
It ignores the input 'n' and just returns 'A'. If you want it to return a different character for each test you will need to tweak the setup.
Perhaps
mockService.Setup(mk => mk.ReturnChar(It.IsAny<int>())).Returns<int>(n => (char)n);
EDIT: Extension to show returning objects (and fixed syntax on previous answer)
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public interface IService
{
Student FindStudentById(int id);
}
[TestMethod]
public void FindStudents()
{
var students = new[]
{
new Student {Id = 1, Name = "Mon" },
new Student {Id = 2, Name = "Tue" },
new Student {Id = 3, Name = "Wed" },
new Student {Id = 4, Name = "Thu" },
};
var mockService = new Mock<IService>();
mockService.Setup(mk => mk.FindStudentById(It.IsAny<int>())).Returns<int>(id => students.First(s => s.Id == id));
Assert.AreEqual("Wed", mockService.Object.FindStudentById(3).Name);
}

Related

Perform xUnit Moq test to create record and save it to DbContext

I am writing test for Web API application written in .NET CORE 3.1. I am using xUnit, AutoFixture & Moq for testing. I have a class that creates a new school instance in the database using Entity Framework/ DbContext. My question is how to mock dbContext & save changes, further my School DataModel has one: many relationships with SchoolBranch DataModel. I have followed this tutorial https://learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking
Error
Message:
Moq.MockException :
Expected invocation on the mock once, but was 0 times: m => m.Add<School>(It.IsAny<School>())
Performed invocations:
Mock<SchoolDbContext:1> (m):
No invocations performed.
Stack Trace:
Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage)
Mock`1.Verify[TResult](Expression`1 expression, Times times)
CreateSchoolCommandTest.ExecuteMethod_ShouldReturnNewGuidId_IfSuccess() line 50
School
public class School
{
public School()
{
this.SchoolBranches = new HashSet<SchoolBranch>();
}
public Guid SchoolID { get; set; }
public string Name { get; set; }
public ICollection<SchoolBranch> SchoolBranches { get; set; }
}
SchoolBranch
public class SchoolBranch
{
public SchoolBranch()
{
}
public Guid SchoolBranchID { get; set; }
public Guid SchoolID { get; set; }
public string Address { get; set; }
public int PhoneNumber { get; set; }
public School School { get; set; }
}
CreateSchool Class
public class CreateSchool : BaseCommand<Guid>, ICreateSchool
{
public SchoolDto SchoolDtos { get; set; }
public CreateSchool(IAppAmbientState appAmbient) : base(appAmbient) { }
public override Guid Execute()
{
try
{
var schoolId = Guid.NewGuid();
List<SchoolBranch> schoolBranches = new List<SchoolBranch>();
foreach(var item in SchoolDtos.SchoolBranchDtos)
{
schoolBranches.Add(new SchoolBranch()
{
SchoolBranchID = Guid.NewGuid(),
SchoolID = schoolId,
Address = item.Address,
PhoneNumber = item.PhoneNumber
});
}
var school = new School()
{
SchoolID = schoolId,
Name = SchoolDtos.Name,
SchoolBranches = schoolBranches
};
schoolDbContext.Schools.Add(school);
schoolDbContext.SaveChanges();
return school.SchoolID;
}
catch(Exception exp)
{
appAmbientState.Logger.LogError(exp);
throw;
}
}
}
Test Class
public class CreateSchoolCommandTest
{
private readonly ICreateSchool sut;
private readonly Mock<IAppAmbientState> appAmbientState = new Mock<IAppAmbientState>();
[Fact]
public void ExecuteMethod_ShouldReturnNewGuidId_IfSuccess()
{
//Arrange
var fixture = new Fixture();
var schoolDtoMock = fixture.Create<SchoolDto>();
var schoolDbSetMock = new Mock<DbSet<School>>();
var schoolBranchDbSetMock = new Mock<DbSet<SchoolBranch>>();
var schoolDbContextMock = new Mock<SchoolDbContext>();
//schoolDbSetMock.Setup(x => x.Add(It.IsAny<School>())).Returns((School s) => s); // this also did not work
schoolDbContextMock.Setup(m => m.Schools).Returns(schoolDbSetMock.Object);
//Act
sut.SchoolDtos = schoolDtoMock;
var actualDataResult = sut.Execute();
// Assert
Assert.IsType<Guid>(actualDataResult);
schoolDbContextMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
}
BaseCommand (DbContext is created here)
public abstract class BaseCommand<T>
{
protected SchoolDbContext schoolDbContext;
protected IAppAmbientState appAmbientState { get; }
public BaseCommand(IAppAmbientState ambientState)
{
this.schoolDbContext = new SchoolDbContext();
this.appAmbientState = ambientState;
}
public abstract T Execute();
}
For fix Error
You made just a little mistake. Insted of
schoolDbContextMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
You should have
schoolDbSetMock.Verify(m => m.Add(It.IsAny<School>()), Times.Once());
schoolDbContextMock.Verify(m => m.SaveChanges(), Times.Once());
Because you use method Add() on schoolDbContext.Schools not on schoolDbContext
For injecting dbContext
Your BaseCoommand class constructor should look like this:
public BaseCommand(IAppAmbientState ambientState, SchoolDbContext schoolDbContext)
{
this.schoolDbContext = schoolDbContext;
this.appAmbientState = ambientState;
}
Your CreateSchool class constructor:
public CreateSchool(IAppAmbientState appAmbient, SchoolDbContext schoolDbContext) : base(appAmbient, schoolDbContext) { }
And next in test you should initialize CreateSchool in test like this:
var sut = new CreateSchool(ambientState, schoolDbContextMock.Object);
And it will work

How to eliminate the looping from below code

I would like to eliminate the loops for better coding and improved performance. So, in below code I need to eliminate loop for test1, test 2, test3.
var test1 = _testP.cdata1(id, sdate)
.Where(t => t.In != null).ToList();
var test2 = _testP.cdata2(id, sdate)
.groupBy(p => p.In.id)
.ToDictionary(p => p.Key, p => p.ToDictionary(q => q.Date, q => q));
var test3 = test1.Select(t =>
{
Dictionary<Date, ClassB> cds = null;
ClassB cd = null;
if (test2.TryGetValue(t.In.Id, out cds)
&& cds.TryGetValue(t.date, out cd))
{
return new Tuple<ClassB, ClassA>(cd, t);
}
return null;
}).Where(p => p != null).ToList();
public IEnumerable<ClassA> cdata1(id, sdate)
{
// do some operations
return listA //(listA is the list of all the elements of ClassA object)
}
public IEnumerable<ClassB> cdata2(id, sdate)
{
// do some operations
return listA //(listA is the list of all the elements of ClassB object)
}
public ClassA
{
public testp in { get; }
public Date date { get; }
// other variables
}
public ClassB
{
public testp in { get; }
public Date date { get; }
// other variables
}
Help me out on writing better code for the above snippet.

Request.GetOwinContext().getManager<ApplicationUserManager> returns null when unit testing Account controller web api

I am trying to write some unit tests for my account controller web apis which make use of UserManager but I keep receiving null on the line in the title in the following section:
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
I have tried so many different ways to fix this as I have read that I need to Mock some of the parts of ApplicationUser but have not managed to get any of them to fix my problem. Below is some of the code I have implemented following a tutorial to unit test:
public interface IStoreAppContext : IDisposable
{
//IDbSet<User> Users { get; }
DbSet<User> u { get; }
DbSet<SportProgram> SportContext { get; set; }
int SaveChanges();
void MarkAsModified(User item);
}
}
The api I am trying to unit test in my account controller is:
(This line below "var user..." is where the problem starts. it calls the line in the title of this question)
[Route("userProfile/{username}")]
public IHttpActionResult getUserProfile(String username)
{
var user = UserManager.FindByName(username);
if (user != null)
{
db2.MarkAsModified(user);
return Ok(user);
}
else
{
return NotFound();
}
}
Then in my TestProject I have the following context class:
class TestStoreAppContext : IStoreAppContext
{
public TestStoreAppContext()
{
this.u = new TestProductDbSet();
}
public DbSet<User> u { get; set; }
public DbSet<SportProgram> SportContext { get; set; }
public int SaveChanges()
{
return 0;
}
public void MarkAsModified(User item) { }
public void Dispose() { }
}
}
Finally in my test controller where i test the api:
[TestMethod()]
public void getUserProfileTest()
{
var context = new TestStoreAppContext();
context.u.Add(GetDemoProduct());
var controller = new AccountController(context);
var result = controller.getUserProfile("john") as OkNegotiatedContentResult<User>;
Assert.AreEqual("john", result.Content.UserName);
}
The GetDemoProduct called above:
User GetDemoProduct()
{
return new User()
{
Id = "3",
UserName = "john",
Password = "Password-1",
};
}
Can anyone point me in the right direction please?

RavenDB MultiMapReduce Sum not returning the correct value

Sorry for this lengthy query, I decided to add the whole test so that it will be easier for even newbies to help me with this total brain-melt.
The using directives are:
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Indexes;
Please leave feedback if I'm too lengthy, but what could possibly go wrong if I add a complete test?
[TestFixture]
public class ClicksByScoreAndCardTest
{
private IDocumentStore _documentStore;
[SetUp]
public void SetUp()
{
_documentStore = new EmbeddableDocumentStore {RunInMemory = true}.Initialize();
_documentStore.DatabaseCommands.DisableAllCaching();
IndexCreation.CreateIndexes(typeof (ClicksBySearchAndProductCode).Assembly, _documentStore);
}
[TearDown]
public void TearDown()
{
_documentStore.Dispose();
}
[Test]
public void ShouldCountTotalLeadsMatchingPreference()
{
var userFirst = new User {Id = "users/134"};
var userSecond = new User {Id = "users/135"};
var searchFirst = new Search(userFirst)
{
Id = "searches/24",
VisitId = "visits/63"
};
searchFirst.Result = new Result();
searchFirst.Result.Rows = new List<Row>(
new[]
{
new Row {ProductCode = "CreditCards/123", Score = 6},
new Row {ProductCode = "CreditCards/124", Score = 4}
});
var searchSecond = new Search(userSecond)
{
Id = "searches/25",
VisitId = "visits/64"
};
searchSecond.Result = new Result();
searchSecond.Result.Rows = new List<Row>(
new[]
{
new Row {ProductCode = "CreditCards/122", Score = 9},
new Row {ProductCode = "CreditCards/124", Score = 4}
});
var searches = new List<Search>
{
searchFirst,
searchSecond
};
var click = new Click
{
VisitId = "visits/64",
ProductCode = "CreditCards/122",
SearchId = "searches/25"
};
using (var session = _documentStore.OpenSession())
{
foreach (var search in searches)
{
session.Store(search);
}
session.Store(click);
session.SaveChanges();
}
IList<ClicksBySearchAndProductCode.MapReduceResult> clicksBySearchAndProductCode = null;
using (var session = _documentStore.OpenSession())
{
clicksBySearchAndProductCode = session.Query<ClicksBySearchAndProductCode.MapReduceResult>(ClicksBySearchAndProductCode.INDEX_NAME)
.Customize(x => x.WaitForNonStaleResults()).ToArray();
}
Assert.That(clicksBySearchAndProductCode.Count, Is.EqualTo(4));
var mapReduce = clicksBySearchAndProductCode
.First(x => x.SearchId.Equals("searches/25")
&& x.ProductCode.Equals("CreditCards/122"));
Assert.That(mapReduce.Clicks,
Is.EqualTo(1));
}
}
public class ClicksBySearchAndProductCode :
AbstractMultiMapIndexCreationTask
<ClicksBySearchAndProductCode.MapReduceResult>
{
public const string INDEX_NAME = "ClicksBySearchAndProductCode";
public override string IndexName
{
get { return INDEX_NAME; }
}
public class MapReduceResult
{
public string SearchId { get; set; }
public string ProductCode { get; set; }
public string Score { get; set; }
public int Clicks { get; set; }
}
public ClicksBySearchAndProductCode()
{
AddMap<Search>(
searches =>
from search in searches
from row in search.Result.Rows
select new
{
SearchId = search.Id,
ProductCode = row.ProductCode,
Score = row.Score.ToString(),
Clicks = 0
});
AddMap<Click>(
clicks =>
from click in clicks
select new
{
SearchId = click.SearchId,
ProductCode = click.ProductCode,
Score = (string)null,
Clicks = 1
});
Reduce =
results =>
from result in results
group result by
new { SearchId = result.SearchId, ProductCode = result.ProductCode }
into g
select
new
{
SearchId = g.Key.SearchId,
ProductCode = g.Key.ProductCode,
Score = g.First(x => x.Score != null).Score,
Clicks = g.Sum(x => x.Clicks)
};
}
}
public class User
{
public string Id { get; set; }
}
public class Search
{
public string Id { get; set; }
public string VisitId { get; set; }
public User User { get; set; }
private Result _result = new Result();
public Result Result
{
get { return _result; }
set { _result = value; }
}
public Search(User user)
{
User = user;
}
}
public class Result
{
private IList<Row> _rows = new List<Row>();
public IList<Row> Rows
{
get { return _rows; }
set { _rows = value; }
}
}
public class Row
{
public string ProductCode { get; set; }
public int Score { get; set; }
}
public class Click
{
public string VisitId { get; set; }
public string SearchId { get; set; }
public string ProductCode { get; set; }
}
My problem here is that I expect Count to be one in that specific test, but it just doesn't seem to add the Clicks in the Click map and the result is 0 clicks. I'm totally confused, and I'm sure that there is a really simple solution to my problem, but I just can't find it..
..hope there is a week-end warrior out there who can take me under his wings.
Yes, it was a brain-melt, for me non-trivial, but still. The proper reduce should look like this:
Reduce =
results =>
from result in results
group result by
new { SearchId = result.SearchId, ProductCode = result.ProductCode }
into g
select
new
{
SearchId = g.Key.SearchId,
ProductCode = g.Key.ProductCode,
Score = g.Select(x=>x.Score).FirstOrDefault(),
Clicks = g.Sum(x => x.Clicks)
};
Not all Maps had the Score set to a non-null-value, and therefore my original version had a problem with:
Score = g.First(x => x.Score != null).Score
Mental note, use:
Score = g.Select(x=>x.Score).FirstOrDefault()
Don't use:
Score = g.First(x => x.Score != null).Score

Mock with Rhino mock -MVVM

I am using Rhino mock for mocking in my test methods. Could someone please see the TODO part in the test method and help me to mock it?
This is my service interface:
public interface ICustomersServiceAgent
{
void GetCustomers(EventHandler<GetCustomersCompletedEventArgs> callback);
void SaveCustomer(POC.Model.Customer cust, EventHandler<SaveCustomerCompletedEventArgs> callback);
}
This is my ViewModel
public class CustomerVM : ViewModelBase
{
private Model.Customer _curentCustomer;
private RelayCommand _saveCommand;
private ICustomersServiceAgent ServiceAgent { get; set; }
private bool isSaved;
private RelayCommand _calculateAgeCommand;
private Decimal age;
private DateTime dateOfBirth;
public CustomerVM(ICustomersServiceAgent serviceAgent)
{
if (serviceAgent == null)
{
ServiceAgent = ServiceManager.GetCustomerServiceManagement();
}
else
{
ServiceAgent =serviceAgent;
}
WireCommands();
}
// if curent object is null then it should be intialize
public Model.Customer CurentCustomer
{
get { return _curentCustomer ?? (_curentCustomer = new Model.Customer()); }
set
{
if (_curentCustomer != value)
{
_curentCustomer = value;
OnPropertyChanged("CurentCustomer");
}
}
}
public RelayCommand CalculateAgeCommand
{
get;
private set;
}
private void WireCommands()
{
SaveCustomerCommand = new RelayCommand(SaveCustomer);
SaveCustomerCommand.IsEnabled = true;
CalculateAgeCommand = new RelayCommand(CalculateAge);
}
private void SaveCustomer()
{
var cus = CurentCustomer;
ServiceAgent.SaveCustomer(cus, (s, e) =>
{
IsSaved = e.Result;
});
}
private void CalculateAge()
{
Age = DateTime.Now.Year - DateOfBirth.Year;
}
public RelayCommand SaveCustomerCommand
{
get;
private set;
}
public bool IsSaved
{
get { return isSaved; }
set
{
isSaved = value;
OnPropertyChanged("IsSaved");
}
}
public decimal Age
{
get { return age; }
set {
age = value;
OnPropertyChanged("Age");
}
}
public DateTime DateOfBirth
{
get { return dateOfBirth; }
set {
dateOfBirth = value;
OnPropertyChanged("DateOfBirth");
}
}
}
I want to test the SaveCustomerCommand in ViewModel above.
So In the my test method, I want to mock the void SaveCustomer(POC.Model.Customer cust, EventHandler<SaveCustomerCompletedEventArgs> callback) method in the ICustomersServiceAgent interface.
This is my test method, see the ToDo part
[TestMethod]
public void SaveCustomerCommandTest()
{
var customerServiceMock = MockRepository.GenerateMock<ICustomersServiceAgent>();
var customerVM = new POC.SilverlightClient.ViewModel.CustomerVM(customerServiceMock);
// TO do : Code to mock SaveCustomer method ///////////////////////////////////
var saveCustomerCommand = customerVM.SaveCustomerCommand;
saveCustomerCommand.Execute(null);
Assert.IsTrue(customerVM.IsSaved);
}
Could someone please explain how I can do this?
I don't see why you need to mock SaveCustomer. All the private SaveCustomer method does is invoke the ServiceAgent service which you already are mocking. I assume the RelayCommand class invokes the delegate you're sending in the constructor parameter which is the call to SaveCustomer. Have you tried running the unit test in your question as-is?
Try following:
customerServiceMock.Stub(sa => sa.SaveCustomer(Arg<POC.Model.Customer>.Is.Anything, Arg<EventHandler<SaveCustomerCompletedEventArgs>>.Is.Anything)).WhenCalled(invocation =>
{
((EventHandler<SaveCustomerCompletedEventArgs>)invocation.Arguments[1])(
customerServiceMock,
new SaveCustomerCompletedEventArgs { Result = true });
});