My test case always fails, tell me where I am wrong, Code is below
public class EmployeeService
{
private readonly IRepository _repository;
public EmployeeService(IRepository repository)
{
_repository = repository;
}
public bool SaveEmployeeData(Employee employee,bool isSaveNeeded)
{
bool result = false;
try
{
if (isSaveNeeded)
{
result= _repository.Save(employee);
}
}
catch (Exception ex)
{
throw new Exception();
}
return result;
}
}
And My test case is
[TestMethod()]
public void SaveEmployeeDataTest()
{
var a = new Mock<IRepository>();
a.Setup(s => s.Save(new Employee())).Returns(true).Verifiable();
var result = new EmployeeService(a.Object).SaveEmployeeData(new Employee(), true);
Assert.IsTrue(result);
}
It always fails.
Use It.IsAny<Employee> to setup Save method parameter
a.Setup(s => s.Save(It.IsAny<Employee>())).Returns(true).Verifiable();
The reason why your test not working is because you have two different employee instances - one for mock setup, and one which is passed to SaveEmployeeData method call. By default those instances will be compared by reference. Moq waits for Save method call with employee instance, which have reference 13 (e.g). But you are passing another employee with reference 42. Thus setup is never invoked.
You have two more options
override Equals and GetHashCode methods of Employee class. Thus Moq will compare employees not by reference, but by business data.
use exactly same instance of employee both for mock setup and SaveEmployeeData method call (preferable way)
Usage of same employee instance:
[TestMethod()]
public void SaveEmployeeDataTest()
{
var a = new Mock<IRepository>();
var sameEmployee = new Employee();
a.Setup(s => s.Save(sameEmployee)).Returns(true).Verifiable();
var service = new EmployeeService(a.Object);
var result = service.SaveEmployeeData(sameEmployee, true);
Assert.IsTrue(result);
}
Overriding equality:
public class Employee
{
public override bool Equals(object obj)
{
Employee other = obj as Employee;
if (other == null)
return false;
return this.Id == other.Id; // for example
}
}
In this case you can leave your test as is.
The new Employee() is creating a new employee instance each time, once for the setup of the Save and another for the actual SaveEmployeeData. Because of this, the employee provided never matches the requirements of the setup.
Either use a catch-all approach like lazyberezovsky's answer, or do the following:
[TestMethod()]
public void SaveEmployeeDataTest()
{
var a = new Mock<IRepository>();
var employee = new Employee();
a.Setup(s => s.Save(employee)).Returns(true).Verifiable();
var result = new EmployeeService(a.Object).SaveEmployeeData(employee, true);
Assert.IsTrue(result);
}
Because the same Employee instance is used in the setup as in the actual invocation, the setup is matched and the correct result returned.
try this -
[TestMethod()]
public void SaveEmployeeDataTest()
{
var a = new Mock<IRepository>();
var employee = new Employee();
a.Setup(s => s.Save(employee)).Returns(true).Verifiable();
var result = new EmployeeService(a.Object).SaveEmployeeData(employee, true);
Assert.IsTrue(result);
}
You need to use the same employee instance in setup as well as method call. This would ensure the verification that your are using the same employee instance which is passed in method and not something created in method or returned from another method.
Related
I'm developing an API which communicates with MongoDB and I need to create some statistics from one collection. I have the following service:
public class BoxService : IBoxService
{
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
_boxCollection = mongoDatabase.GetCollection<Box>(dbSettings.Value.BoxCollectionName);
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var results = await _boxCollection.AsQueryable()
.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty })
.ToListAsync();
// More calculations with the results list
return boxNumberStatisticsList;
}
}
And the following test:
public class BoxServiceTest
{
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
private readonly IBoxService _boxService;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_boxes = new List<Box> {...};
var mockOptions = A.Fake<IOptions<DbSettings>>();
var mongoClient = A.Fake<IMongoClient>();
var mongoDb = A.Fake<IMongoDatabase>();
A.CallTo(() => mongoClient.GetDatabase(A<string>._, default)).Returns(mongoDb);
A.CallTo(() => mongoDb.GetCollection<Box>(A<string>._, default)).Returns(_boxCollection);
_boxService = new BoxService(mockOptions, mongoClient);
}
}
This is working so far, the BoxService is created with the fake parameters and I can test other functionalities of the service (FindAll, FindById, Create, etc.) but how can I test the GetBoxNumberStatisticsAsync function? I can't fake the AsQueryable because it's an extension method.
As you've noted, you can't fake an extension method. This question is asked every once in a while. For example, see Faking an Extension Method in a 3rd Party Library. There are a few approaches:
if the static method is simple enough, to divine what it does and fake the non-static methods that it calls
add a layer of indirection: wrap the call to the extension method in an interface that you can fake
don't fake the database. Instead, replace it with some in-memory analogue, if one exists (I don't know what's available for Mongo)
Here is what I ended up with. A base interface for all my services:
public interface IBaseService<T>
{
//generic method definitions for all services: Findall, FindById, Create, Update
}
An abstract class to have a generic constructor:
public abstract class BaseService<T> : IBaseService<T>
{
protected BaseService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient, string collectionName)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
Collection = mongoDatabase.GetCollection<T>(collectionName);
}
protected IMongoCollection<T> Collection { get; }
// abstract method definitions for IBaseService stuff
public virtual async Task<List<T>> CollectionToListAsync()
{
return await Collection.AsQueryable().ToListAsync();
}
}
An interface for my BoxService:
public interface IBoxService : IBaseService<Box>
{
public Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync();
}
The service itself:
public class BoxService : BaseService<Box>, IBoxService
{
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
: base(dbSettings, mongoClient, dbSettings.Value.BoxCollectionName)
{
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var list = await CollectionToListAsync();
var results = list.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty }).ToList();
//...
return boxNumberStatisticsList;
}
}
And finally the test:
public async Task GetBoxNumberStatisticsAsync_ReturnsStatistics()
{
// Arrange
var expected = new List<BoxStatisticsDto> {...};
var fakeService = A.Fake<BoxService>(options => options.CallsBaseMethods());
A.CallTo(() => fakeService.CollectionToListAsync()).Returns(_boxes);
// Act
var boxList = await ((IBoxService)fakeService).GetBoxNumberStatisticsAsync();
// Assert
}
I'm not a huge fan of making the CollectionToListAsync public, but nothing really worked for me here. I tried creating IQueryable and IEnumerable from my list and convert them to IMongoQueryable but no success. I also tried faking the IMongoQueryable but I couldn't execute the Select on it as it gave an error that the 'collectionNamespace' can't be null and the CollectionNamespace can't be faked, because it's a sealed class.
I've a class with several services injected in its constructor. I'm using Autofixture with xUnit.net and NSubstitute, and created an attribute to setup the global customization.
public class AutoDbDataAttribute : AutoDataAttribute
{
public AutoDbDataAttribute() : base(() => new Fixture().Customize(new AutoNSubstituteCustomization()))
{
}
public AutoDbDataAttribute(Type customizationType) : base(() =>
{
var customization = Activator.CreateInstance(customizationType) as ICustomization;
var fixture = new Fixture();
fixture.Customize(new AutoNSubstituteCustomization());
fixture.Customize(customization);
return fixture;
})
{
}
}
I also have a custom customization class that setups the common customization for the test methods in the same class.
public class RevenueProviderCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<IRevenueContextService>(() =>
{
var contextService = Substitute.For<IRevenueContextService>();
contextService.GetContext().Returns(fixture.Create<RevenueContext>());
return contextService;
});
fixture.Register<ICompanyService>(() =>
{
var companyService = Substitute.For<ICompanyService>();
companyService.Get(Arg.Any<Guid>()).Returns(fixture.Create<Company>());
return companyService;
});
}
}
Now, some of my tests depend on modifying specific properties in the objects returned by the services. So in some cases, I want to modify the RevenueContext and in some cases, I want to modify the Company data.
What I did was creating another object inside the test itself and modify the Returns of the service with the new object, like this:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(RevenueProvider sut, Company company, [Frozen]IRevenueContextService contextService)
{
var fixture = new Fixture();
RevenueContext context = fixture.Build<RevenueContext>().With(c => c.DepartmentId, null).Create();
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
But this doesn't work. The RevenueContext from the RevenueProviderCustomization is still used.
Does anyone know how I can override the return from the service? I don't want to setup the fixture one by one in my test, so I was hoping to be able to create a 'general setup' and modify as needed according to the test case.
UPDATE 1
Trying the answer from Mark, I changed the test to
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue([Frozen]IRevenueContextService contextService, [Frozen]Company company, RevenueProvider sut, RevenueContext context)
{
context.DepartmentId = null;
contextService.GetContext().Returns(context);
sut.GetRevenue().Should().Be(company.Revenue);
}
The problem is because the RevenueContext is called in the RevenueProvider constructor. So my modification to the DepartmentId happens after the call was made.
public RevenueProvider(IRevenueContextService contextService, ICompanyService companyService)
{
_contextService = contextService;
_companyService = companyService;
_company = GetCompany();
}
public double GetRevenue()
{
if (_hasDepartmentContext)
return _company.Departments.Single(d => d.Id == _departmentId).Revenue;
else
return _company.Revenue;
}
private Company GetCompany()
{
RevenueContext context = _contextService.GetContext();
if (context.DepartmentId.HasValue)
{
_hasDepartmentContext = true;
_departmentId = context.DepartmentId.Value;
}
return _companyService.Get(context.CompanyId);
}
Assuming that RevenueProvider essentially looks like this:
public class RevenueProvider
{
private readonly ICompanyService companySvc;
public RevenueProvider(ICompanyService companySvc)
{
this.companySvc = companySvc;
}
public object GetRevenue()
{
var company = this.companySvc.Get(Guid.Empty);
return company.Revenue;
}
}
Then the following test passes:
[Theory]
[AutoDbData(typeof(RevenueProviderCustomization))]
public void ShouldReturnCompanyRevenue(
[Frozen]ICompanyService companySvc,
RevenueProvider sut,
Company company)
{
companySvc.Get(Arg.Any<Guid>()).Returns(company);
var actual = sut.GetRevenue();
Assert.Equal(company.Revenue, actual);
}
This scenario is exactly what the [Frozen] attribute is designed to handle. The various attributes that AutoFixture defines are applied in the order of the arguments. This is by design, because it enables you to pull out a few values from the argument list before you freeze a type.
In the OP, [Frozen] is only applied after sut, which is the reason the configuration of the mock doesn't apply within the SUT.
So I am new to TDD and here is my problem:
I have a class with several methods. Something like this:
public class CompanyService : ICompanyService
{
public ICompanyRepository companyRepository;
public CompanyService() : this(new CompanyRepository())
{
}
public CompanyService(ICompanyRepository repository)
{
companyRepository = repository;
}
public virtual bool InsertCompany(Company company)
{
return companyRepository.InsertCompany(company);
}
public bool InsertCompany(Company company, int total)
{
if (AddTotals(total))
{
return this.InsertCompany(company);
}
return false;
}
/// <summary>
/// Wrapper for the static method at static service
/// </summary>
/// <param name="total"></param>
/// <returns></returns>
public virtual bool AddTotals(int total)
{
return StaticService.AddTotals(total);
}
}
Most of my tests run fine for this class. So here is my unit test:
[TestMethod]
public void Test_Unit_AddTotals()
{
var service = new CompanyService();
Assert.IsFalse(service.AddTotals(1));
}
[TestMethod]
public void Test_Unit_InsertCompany_IsExecuted()
{
Guid id = GenerateCustomerID();
var company = new Company { CustomerID = id, CompanyName = "CFN-" + id };
var mock = new Mock<CompanyService>();
mock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
mock.Object.InsertCompany(company, 1);
mock.Verify(t => t.InsertCompany(It.IsAny<Company>()),Times.Once);
}
[TestMethod]
public void Test_Unit_InsertCompany_IsSuccess()
{
Guid id = GenerateCustomerID();
var company = new Company { CustomerID = id, CompanyName = "CFN-" + id };
var mock = new Mock<CompanyService>();
mock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
mock.Setup(t => t.InsertCompany(It.IsAny<Company>(), It.IsAny<int>())).Returns(true);
Assert.IsTrue(mock.Object.InsertCompany(company, 1));
}
[TestMethod]
public void Test_Unit_StaticService()
{
var rep = new Mock<ICompanyRepository>();
rep.Setup(t => t.InsertCompany(It.IsAny<Company>())).Returns(true);
var serviceMock = new Mock<ICompanyService>();
serviceMock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
Assert.IsTrue(serviceMock.Object.AddTotals(0));
}
private Guid GenerateCustomerID()
{
return Guid.NewGuid();
}
So when I make my 2 parameter InsertCompany method virtual my IsExecuted method fails at Verify, if I make it non-virtual, then I can't mock it for IsSuccess method and it fails..
Could you please tell me what I am missing with your TDD expertise?
As has been suggested in the comments, you're almost certainly not testing the right thing. Look at this test:
[TestMethod]
public void Test_Unit_InsertCompany_IsSuccess()
{
Guid id = GenerateCustomerID();
var company = new Company { CustomerID = id, CompanyName = "CFN-" + id };
var mock = new Mock<CompanyService>();
mock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
mock.Setup(t => t.InsertCompany(It.IsAny<Company>(), It.IsAny<int>())).Returns(true);
Assert.IsTrue(mock.Object.InsertCompany(company, 1));
}
If your class is marked with the right virtual state for the Setup to execute, then you're not actually testing any of your class at all. You're setting up the Mock to return true when a method is called, then asserting that when you call the method the mock returns true... You're just testing that you've set your Mocks up correctly.
When you mark the method as virtual, your mocking used in the IsExecuted method is failing, because you're calling virtual methods from within the class under test. If you don't tell it to, Moq will assume that if you're doing a partial mock, you only want your mocked virtuals to be called, not the existing implementation. You can override this by telling Moq to call your existing implementation by setting the CallBase flag.
Your test would then become this:
[Test]
public void Test_Unit_InsertCompany_IsExecuted() {
Guid id = GenerateCustomerID();
var company = new Company { CustomerID = id, CompanyName = "CFN-" + id };
var mock = new Mock<CompanyService>();
mock.CallBase = true;
mock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
mock.Setup(t => t.InsertCompany(It.IsAny<Company>()));
mock.Object.InsertCompany(company, 1);
mock.Verify(t => t.InsertCompany(It.IsAny<Company>()), Times.Once);
}
Two things to note are
In the above test, CallBase=true is used to execute existing code.
As a result of 1, it's necessary to perform a Setup for the call you want to verify, otherwise the call will actually execute the underlying code and call out to the repository.
Testing that one method calls another method in the same class isn't really a great idea. It can get very messy and makes it difficult to know that what you're expecting to happen is actually what's happening as well as tightly coupling your implementation to your test code.
You've already setup your Company class to allow the injection of a repository. Testing that the appropriate repository interactions take place would result in less coupling to the implementation of your Company class and would probably result in more straightforward mocking.
Using that approach, your IsExecuted test might become:
[Test]
public void Test_Unit_InsertCompany_SavesToRepository() {
Guid id = GenerateCustomerID();
var repoMock = new Mock<ICompanyRepository>();
var company = new Company { CustomerID = id, CompanyName = "CFN-" + id };
var mock = new Mock<CompanyService>(repoMock.Object);
mock.CallBase = true;
mock.Setup(t => t.AddTotals(It.IsAny<int>())).Returns(true);
mock.Object.InsertCompany(company, 1);
repoMock.Verify(t => t.InsertCompany(It.IsAny<Company>()), Times.Once);
}
Ideally, you'd be able to Mock the interaction with StaticService.AddTotals, that way you would be able to instantiate an actual CompanyService, rather than a mock object in your tests, however that seems out of scope for your current problem...
I'm not sure if I'm using Moq the right way, so if anyone could help, I'd be grateful.
I want to test the call of Clone() method on object in a collection. The test looks like this:
[Test]
public void CloneTest()
{
var mdFake = new Mock<MachineDecision>();
var clonable = mdFake.As<ICloneable>();
clonable.Setup(x => x.Clone()).Verifiable();
var decision = new Decision()
{
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
var newDecision = (Decision) decision.Clone();
clonable.Verify(x => x.Clone());
}
The test fails: Moq.MockException :
Expected invocation on the mock at least once, but was never performed: x => x.Clone() but I believe it should actually pass.
Used classes look as follows:
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item => (MachineDecision) item.Clone()).ToList();
}
return obj;
}
}
public class MachineDecision : Entity<Guid>, ICloneable
{
//...
}
There are two options available.
First, you can make an implementation of method Clone() virtual and your test will be 'Green'
public class MachineDecision : Entity<Guid>, ICloneable
{
public virtual object Clone()
{
throw new NotImplementedException();
}
}
Second, you can invoke Clone() method from ICloneable interface: (MachineDecision)(item as ICloneable).Clone(); and your test will be 'Green' also.
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item =>
{
return (MachineDecision)(item as ICloneable).Clone();
}).ToList();
}
return obj;
}
}
I realise that now it is not the best code but it is up to you how to refactor it further.
I'd do it like this:
[Test]
public void CloneTest()
{
// create the mock
var mdFake = new Mock<MachineDecision>();
var decision = new Decision
{
// setup (pass it to my collection)
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
// call the method being tested (you need to make Clone() virtual)
decision.Clone();
// check for the side effects -> It was called once !
mdFake.Verify(x => x.Clone(), Times.Once());
}
I hope this helps you.
EDIT - I'm sorry, as it was pointed in the comments - I forgot to mention, that what I'm suggesting requires you to make Clone() (in MachineDecision) - virtual, which might not be ideal in your case.
Try this:
...
clonable.Expect(x => x.Clone()).Verifiable().Returns(null);
...
clonable.Verify();
I've have searched on this and it seems to be a catch all, unfortunately everything I've read doesn't help figure it out. Here is the class:
public interface IMockInterface
{
MockClass MockedMethod();
MockClass MockThis();
}
public class MockClass : IMockInterface
{
public virtual MockClass MockedMethod()
{
MockClass returnValue;
returnValue = new MockClass();
returnValue.SomeMessage = "Not mocked";
return returnValue;
}
public MockClass MockThis()
{
MockClass mock;
MockClass returnValue;
mock = new MockClass();
return mock.MockedMethod();
}
}
And the test:
public void MockTest_Internal()
{
MockClass mainClass;
MockClass returnedClass;
IMockInterface mockProvider;
mainClass = new MockClass();
mockProvider = repository.StrictMock<IMockInterface>();
Expect.Call(mockProvider.MockedMethod())
.Return(new MockClass { SomeMessage = "Mocked" });
repository.ReplayAll();
returnedClass = mainClass.MockThis();
provider.AssertWasCalled(item => item.MockedMethod());
Assert.IsTrue(returnedClass.SomeMessage == "Mocked");
}
And have also tried and doesn't work
But I keep getting this exception:
Rhino.Mocks.Exceptions.ExpectationViolationException:
IMockInterface.MockedMethod(); Expected #1, Actual #0
Now from what I've read this would suggest either the method was called with different than expected parameters OR the method was never called but was expected to be called. This isn't the case for the test.
Side Note: This is my first time really using Rhino.Mocks without some in house code so I am basically picking it up as I go. There could be something really stupid here...
This was the old test commented on, but is not what I should have been using:
public void MockTest_Internal()
{
MockClass mainClass;
MockClass returnedClass;
IMockInterface mockProvider;
mainClass = new MockClass();
var provider = MockRepository.GenerateStub<IMockInterface>();
provider.Stub(item => item.MockedMethod())
.Return(new MockClass { SomeMessage = "Mocked" });
returnedClass = mainClass.MockThis();
provider.AssertWasCalled(item => item.MockedMethod());
Assert.IsTrue(returnedClass.SomeMessage == "Mocked");
}
You're telling the mock framework to stub the MockedMethod class on the provider object, but you never inject the provider into the mainClass object to be used. It's not clear to me what you are trying to accomplish but if you want the mocked method to be called then it has to be called on the object on which the stub was set up.
If you define MockThis as below, I think you will find that it will work.
public MockClass MockThis(IMockInterface provider)
{
return provider.MockMethod();
}
The bottom line is that you get the exception because the method was never called on the provider, only on the mainClass object.
EDIT: Example
public class ClassUnderTest
{
private ProviderClass provider { get; set; }
public ClassUnderTest( ProviderClass provider )
{
this.Provider = provider;
}
public int DoOperation()
{
return this.Provider.ProviderOperation();
}
}
public class ProviderClass
{
private int value = 42;
public ProviderClass()
{
}
public virtual int ProviderOperation()
{
return this.value;
}
}
[TestMethod]
public void DoOperationTest()
{
ProviderClass mockProvider = MockRepository.GenerateMock<ProviderClass>();
mockProvider.Expect( mp => mp.ProviderOperation() ).Return( -1 );
ClassUnderTest target = new ClassUnderTest( mockProvider );
int expectedValue = -1;
int value = target.DoOperation();
Assert.AreEqual( expectedValue, value );
mockProvider.VerifyAllExpectations();
}
Normally the ProviderClass object would return 42 from the ProviderOperation method, but we've mocked it out and told it to return -1. When the ClassUnderTest DoOperation method is called, the mock provider object's ProviderOperation method is invoked and returns the mocked value of -1.
Hope this helps.
I usually get this error when a stubbed method is called with an object argument that I build in the test and in the tested code the object is built before calling that method. The solution is to use the Rhino.Mocks Matches().
Ex:
Arg<string>.Matches(s => s.Contains("some substring"))