I'm trying to create a unit test using Moq and xUnit. The operation is very straightforward: calculate the number of days in a date range and update an object property. This works in integration testing, however the object property is not updated in my unit test
Unit Test:
[Fact]
public void Bill_DayCount_IsCorrect()
{
// Arrange
Mock<IRepository> mockRepo = new Mock<IRepository>();
Bill bill = new Bill
{
StartDate = DateTime.Parse("2/1/2018"),
EndDate = DateTime.Parse("3/1/2018"),
};
// Act
mockRepo.Object.GetBillDayCount(bill);
// Assert
// Here the bill.DayCount value = 0
Assert.Equal(28, bill.DayCount);
}
The method in the repo:
public Bill GetBillDayCount(Bill bill)
{
bill.DayCount = (bill.EndDate - bill.StartDate).Days;
return bill;
}
You don't need to mock the class which is the target of your test. You can use the concrete implementation of Repository.
You only need to mock the external dependencies that the target class uses.
Interface
public interface IRepository
{
Bill GetBillDayCount(Bill bill);
}
Class
public class Repository : IRepository
{
public Bill GetBillDayCount(Bill bill)
{
bill.DayCount = (bill.EndDate - bill.StartDate).Days;
return bill;
}
}
Test
[Fact]
public void Bill_DayCount_IsCorrect()
{
// Arrange
var repository = new Repository();
var bill = new Bill
{
StartDate = DateTime.Parse("1/1/2018"),
EndDate = DateTime.Parse("29/1/2018"),
};
// Act
var result = repository.GetBillDayCount(bill);
// Assert
Assert.Equal(28, result.DayCount);
}
Related
I have such service as below. Let's say i want to test Create() method. I read that in unit testing i should test by comparing, counting and so on. How could i then test my Create() method. Is it ugly to change return type from void Create to bool Create just to be able to check method output for testing purpose or that's not ideal idea? Can you propose something?
public class CreateCarService : ICreateCarService
{
private readonly ICarQuery _carQuery;
private readonly ICarRepository _carRepository;
public CreateCarService(ICarQuery carQuery, ICarRepository carRepository)
{
_carQuery = carQuery;
_carRepository = carRepository;
}
public void Create(Car car)
{
if (car == null) throw new CusException(Error, "Car object cannot be null");
if (_carQuery.IsLoginExist(car.Login))
throw new CusException(Error, "Message1");
if (_carQuery.IsEmailExist(car.Email))
throw new CusException(Error, "Message1");
_carRepository.Add(car);
}
}
You might verify that for any valid Car instance Add method was called only once, by setting up the Moq behavior of IsLoginExist and IsEmailExist method an using a Verify method
[TestFixture]
public class Test
{
[Test]
public void CreateCarServiceTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(false);
createCarService.Create(new Car());
carRepositoryMock.Verify(c => c.Add(It.IsAny<Car>()), Times.Once);
}
}
It also makes sense to check a negative cases, when Create method throws an exception
[Test]
public void CreateCarNegativeTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
Assert.Throws<CusException>(() => createCarService.Create(null));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
}
You can split this method into different tests to have one Assert per test, or pass the parameters to it.
You want to test the "expected behavior" of the member under test. Since the member under test does not return any verifiable output and has a dependency on external abstractions, you should be able to monitor the interaction of the member under test with that external abstractions and verify the expected behavior
One such example
public void CreateCarService_Create_Should_Add_Car() {
//Arrange
Car car = new Car {
Login = "Login",
Email = "Email"
};
ICarQuery carQuery = Mock.Of<ICarQuery>();
ICarRepository carRepository = Mock.Of<ICarRepository>();
ICreateCarService subject = new CreateCarService(carQuery, carRepository);
//Act
subject.Create(car);
//Assert
Mock.Get(carRepository).Verify(_ => _.Add(car), Times.Once);
}
The example above safely navigates through to the end of the member under test but lets say you wanted to test the exception is thrown for the null parameter case.
public void CreateCarService_Create_Should_Throw_CusException_For_Null_Car() {
//Arrange
ICreateCarService subject = new CreateCarService(null, null);
//Act
Action act = ()=> subject.Create(null);
//Assert
var ex = Assert.Throws<CusException>(act);
}
You want to create tests for all the possible paths through the member under test. So take some time and review the subject under test and work out the possible test cases. Arrange the subject to satisfy those cases and exercise those cases to verify the expected behavior.
Reference Moq Quickstart to get a better understanding of how to use the Moq mocking framework.
You don't need to change it to bool, just to test. A simple way you can do this is:
[TestFixture]
public class Test
{
CreateCarService createCarService;
ICarRepository carRepositoryMock;
[Setup]
public void InitializeTest()
{
var carQueryMock = new Mock<ICarQuery>();
carRepositoryMock = new Mock<ICarRepository>();
createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
}
[Test]
public void CreateCarShouldThrowIfNull()
{
//arrange
Car car =null;
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
[Test]
public void CreateCarShouldThrowForInvalidLogin()
{
//arrange
var car = new Car()
{
Login=null,
Email="Email"
};
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
And So on.
You can use Assert.Throw for invalid car objects or Assert.DoesNotThrow for valid car objects. Finally, you can test if the car was added to the repository by:
[Test]
public void CreateCarShouldAddCarToRepo()
{
//arrange
var car = new Car()
{
Login="Login",
Email="Email"
};
//act
createCarService.CreateCar(car);
var carRetrieved =carRepositoryMock.GetCar(car.id);//depending on your implementation
//assert
Assert.AreSame(car,carRetrieved);
}
I am new to write Unit Tests. Therefore, I have been struggling with.
I need to insert product via an external WebService. Then the WebService will return a string that is necessary to update the product afterwards.
This is my ApiController:
public class ProductController : ApiController
{
private IProductRepository _ProductRepository;
private IWebService _WebService;
public ProductController(IProductRepository productRepository, IWebService webService)
{
_ProductRepository = productRepository;
_WebService = webService;
}
public HttpResponseMessage Add(string title)
{
using (TransactionScope scope = new TransactionScope())
{
Product product = new Product
{
Title = title
};
this._ProductRepository.Add(product);
// WebService will return a string
string result = this._WebService.Add(product.ID, DateTime.Now);
product.ServiceResult = result;
this._ProductRepository.Update(product);
scope.Complete();
}
return Request.CreateResponse(HttpStatusCode.Created);
}
}
I was wondering how should I write a unit test for this code?
I've tried to write it as follows: (with NUnit, Moq)
[TestFixture]
public class ProductControllerShould : AssertionHelper
{
private Mock<IWebService> _WebService;
private Mock<IProductRepository> _ProductRepository;
[SetUp]
public void Setup()
{
_WebService = new Mock<IWebService>();
_ProductRepository = new Mock<IProductRepository>();
}
[Test]
public void ReturnCreatedOnAdd()
{
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object);
var result = controller.Add("Lumia");
Expect(result, Is.EqualTo(HttpStatusCode.Created));
}
}
but when I debug the test, result in this line is null that is not correct.
string result = this._WebService.Add(product.ID, DateTime.Now);
Shouldn't this line handle the behaviour of _WebService.Add() and return "0"?
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
I know I write the test incorrectly but I don't know what should I do.
Thanks.
The problem here, is that you are mocking call of static method `DateTime.Now' . But "Now" in the time point of mocking and as it is called are different. Therefore your call doesn't return anything.
I could suggest 3 following ways:
1) It doesn't really matter for you, if the call was with DateTime.Now or not, in that case you could ignore the second argument:
_WebService.Setup(b => b.Add(1, It.IsAny<DateTime>())).Returns("0");
2) You want to test, that the call was with DateTime.Now. In that case i create an interface for getting DateTime.Now:
public interface IDateTimeNowProvider
{
DateTime Now { get; }
}
public ProductController(IProductRepository productRepository,
IWebService webService,
IDateTimeNowProvider dateTimeNowProvider)
{
_ProductRepository = productRepository;
_WebService = webService;
_dateTimeNowProvider = dateTimeNowProvider;
}
In production code you use default implementation of it, that just returns DateTime.Now. But in your test class you do mock this interface with some predefined values and you test for using this value.
var now = DateTime.Parse("2017-01-22");
var _dateTimeNowProvider = new Mock<IDateTimeNowProvider>();
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object, _dateTimeNowProvider.Object );
_dateTimeNowProvider.Setup(x => x.Now).Returns(now);
_WebService.Setup(b => b.Add(1,now)).Returns("0");
3) You could use special mocking framework that allows to mock static methods, as for example typemock isolator
This is my first post!
I'm trying to write a unit test using nsubstitute but I'm finding the last bit difficult.
I've included a snippet of code below, the test fails when calling the method on the model. Is it possible to stub this method out? Similar to if it was an interface
Cheers guys! Look forward to your responses
James
My unit test attempt
public class MyTests
{
private IModelMapper _modelMapper;
[SetUp]
public void Setup()
{
_modelMapper = Substitute.For<IModelMapper>();
}
[Test]
public void GetModel_Returns_A_Model()
{
var result = theClass.GetModel(new Booking {CurrencyCode = ""}, null);
**UPDATE to include assert**
// Assert
Assert.IsInstance<BasketModel>(result);
}
}
Feature code
public Model GetModel(Booking booking)
{
var model = _modelMapper.Map(booking);
// Is it possible to stub this out? Similar to if it was an interface
model.FormatPricing(somethingHere);
return model;
}
UPDATE - to illustrate return type
BasketModel model = _modelMapper.Map(booking);
UPDATE #2 - to include return
var basketModel = new BasketModel();
BasketModel model = _modelMapper.Map(booking).Returns(basketModel);
Can you include what test failure message you're getting?
Here is the general approach I tend to take for this kind of code. Say we're injecting the IModelMapper into the class-under-test (approximate code; I haven't tested):
[SetUp]
public void Setup()
{
_modelMapper = Substitute.For<IModelMapper>();
theClass = new TheClass(_modelMapper);
}
[Test]
public void GetModel_Returns_Model_From_Mapper()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = new BasketModel();
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
Assert.AreSame(expectedModel, result);
}
If you want to stub out BasketModel.FormatModel (that's a big "if". I would recommend using the real type if possible) then you'll want to substitute for BasketModel too.
Be careful - NSubstitute will not work with non-virtual methods, so you may want an interface for BasketModel, or just make sure to use virtual everywhere. (Again, untested code ahead)
[Test]
public void ModelReturnedShouldBeFormatted()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = Substitute.For<IBasketModel>();
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
expectedModel.Received().FormatModel(Arg.Any<SomethingHere>());
}
This is testing adherence to a particular contract - TheClass will call FormatModel on the BasketModel returned from the mapper. If you need to duplicate some implementation in the test (again, this is generally discouraged), you can use When..Do:
[Test]
public void FormatModel()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = Substitute.For<IBasketModel>();
expectedModel
.When(x => x.FormatModel(Arg.Any<SomethingHere>()))
.Do(/* some action */);
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
// assertion here that depends on "some action" and result
}
Hope this helps.
I have two tests. First test work correctly. Second test looks like as first test. However, I get exception, when I run the second test.
The first test:
public void GetCurrentBalance_Should_getting_rigth_balanse()
{
// Arrange
double balance = 10;
var mocks = new MockRepository();
IUnitOfWork unitOfWork = mocks.Stub<IUnitOfWork>();
unitOfWork.Stub(svc => svc.AccountRepository.Get()).Return(new List<Account> {new Account { Balance = balance }});
AccountService accountService = new AccountService(unitOfWork);
// Act
mocks.ReplayAll();
var result = accountService.GetCurrentBalance();
//Assert
Assert.AreEqual(balance, result);
}
The second test:
public void WithdrawMoney_Balance_should_decrease_when_money_been_withdrawn()
{
// Arrange
double balance = 10;
var mocks = new MockRepository();
IUnitOfWork unitOfWork = mocks.Stub<IUnitOfWork>();
unitOfWork.Stub(svc => svc.AccountRepository.Get()).Return(new List<Account> { new Account { Balance = balance } });
AccountService accountService = new AccountService(unitOfWork);
// Act
mocks.ReplayAll();
var result = accountService.WithdrawMoney(1); // this line is different
//Assert
Assert.AreEqual(balance - 1, result);
}
Part of my service:
public class AccountService : BaseService, IAccountService
{
public AccountService(IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
public double WithdrawMoney(double amountOfMoney)
{
var currentBalance = GetCurrentBalance();
if (currentBalance < amountOfMoney)
{
throw new BusinessLayerException("error!");
}
var lastAccount = GetLastAccount();
if (lastAccount == null)
{
throw new BusinessLayerException("error!");
}
lastAccount.Balance -= amountOfMoney;
unitOfWork.AccountRepository.Update(lastAccount);
unitOfWork.Save();
return lastAccount.Balance;
}
public double GetCurrentBalance()
{
var lastAccount = GetLastAccount();
if (lastAccount == null)
{
return 0;
}
return lastAccount.Balance;
}
private Account GetLastAccount()
{
var lastAccount = unitOfWork.AccountRepository.Get().FirstOrDefault();
return lastAccount;
}
}
I get the following call stack:
Rhino.Mocks.Exceptions.ExpectationViolationException : IUnitOfWork.get_AccountRepository(); Expected #1, Actual #2.
at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.DoGetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.MethodRecorders.MethodRecorderBase.GetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.ReplayMockState.DoMethodCall(IInvocation invocation, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.ReplayMockState.MethodCall(IInvocation invocation, MethodInfo method, Object[] args)
at Rhino.Mocks.MockRepository.MethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.Invocation.Actions.RegularInvocation.PerformAgainst(IInvocation invocation)
at Rhino.Mocks.Impl.RhinoInterceptor.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IUnitOfWorkProxy2936ffa6dea844258ad88f7a7e99dbc0.IUnitOfWork.get_AccountRepository()
at Service.AccountService.GetLastAccount() in AccountService.cs: line 90
at Service.AccountService.WithdrawMoney(Double amountOfMoney) in AccountService.cs: line 61
at ServiceTest.AccountServiceTest.WithdrawMoney_Balance_should_decrease_when_money_been_withdrawn() in AccountServiceTest.cs: line 48
follow below rules for Rhione mock test
for using Rhino Mocks just follow the steps as under with Mock Object:
1.Create mock by: mockrepository.CreateMock();
2.Record your expactations: in Record Block.
3.call ReplayAll to tell rhino Mocks that you are done with recording
4.MOST IMP. STEP:Call expected method here for example: mockMyRhinoImplementation.HelloRhinoMocks(“ABC”)
NOTE: Must need to pass the same arguments what you have recorded else it will again throw ExpectationViolationException.
5.Call VerifyAll();
So, the differene between both the tests are tht one method is having argument and the another does not have...try to use like below
double number = 1;
var result = accountService.WithdrawMoney(number);
I fix my problem by changing the second test. I change one line:
from:
IUnitOfWork unitOfWork = mocks.Stub<IUnitOfWork>();
to:
IUnitOfWork unitOfWork = mocks.DynamicMock<IUnitOfWork>();
But it seems to me that this is a bad solution to my problem.
I have a method whose operations depend on its dependents, like below. Is it still value doing unit test? Because the unit test is not testing any business logic, rather by mocks.
Unit test below:
Please note that the method's opetions is determined by expectedCustomerValidality, which is setup by the test. Mostly, the logic is determined by mocks (e.g. Setup(c => c.IsValid()).
[Test]
[TestCase(true)]
[TestCase(false)]
public void AddCustomer(bool expectedCustomerValidality)
{
//using Moq
companyRepositoryMock.Setup(c => c.GetById(It.IsAny<int>())).Returns(new Company());
customerValidatorMock.Setup(c => c.IsValid(It.IsAny<Customer>())).Returns(expectedCustomerValidality);
var customer = new Customer
{
Firstname = "firstName",
Surname = "surname",
Company = new Company { Id = 1 }
};
var addCustomer = customerServiceSut.AddCustomer(customer);
Assert.AreEqual(expectedCustomerValidality,addCustomer);
}
Production code below:
public class CustomerService : ICustomerService
{
private ICompanyRepository companyRepository;
private ICustomerRepository customerRepository;
private ICustomerValidator customerValidator;
public CustomerService(ICompanyRepository companyRepository, ICustomerRepository customerRepository, ICustomerValidator customerValidator)
{
this.companyRepository = companyRepository;
this.customerRepository = customerRepository;
this.customerValidator = customerValidator;
}
public bool AddCustomer(Customer customer)
{
customer.Company = companyRepository.GetById(customer.Company.Id); ;
if (customerValidator.IsValid(customer))
{
customerRepository.AddCustomer(customer);
return true;
}
return false;
}
}
Questions:
Is AddCustomer() required unit-testing?
If so, is the current unit test performing the correct way?
1 If not, what is the proper way to unit test it?
I don't like this. Here's why: your test method names should reflect the method under test, what the preconditions of the test are, and what you expect the result of the test to be:
public bool AddCustomer_CustomerIsValid_ShouldReturnTrue()
public bool AddCustomer_CustomerIsInvalid_ShouldReturnFalse()
Now if you want to, you can refactor the core testing logic into its own method to eliminate the code duplication, and then call that method from the two above methods. But the refactored method is not a test case; it's just a helper method for the actual test cases.
Example:
[Test]
public void AddCustomer_CustomerIsValid_ShouldReturnTrue()
{
var result = AddCustomerTest(true);
Assert.IsTrue(result);
}
[Test]
public void AddCustomer_CustomerIsInvalid_ShouldReturnFalse()
{
var result = AddCustomerTest(false);
Assert.IsFalse(result);
}
public void AddCustomerTest(bool expectedCustomerValidality)
{
//using Moq
companyRepositoryMock.Setup(c => c.GetById(It.IsAny<int>())).Returns(new Company());
customerValidatorMock.Setup(c => c.IsValid(It.IsAny<Customer>())).Returns(expectedCustomerValidality);
var customer = new Customer
{
Firstname = "firstName",
Surname = "surname",
Company = new Company { Id = 1 }
};
var result= customerServiceSut.AddCustomer(customer);
return result;
}
AddCustomer requires testing, as it performs a business logic - it retrieves a company, and sets it, it validates the data, it adds the data to the repository, and it returns a result.
Your test is almost correct. I would make it a little bit more specific, to verify all the business logic:
[Test]
[TestCase(true)]
[TestCase(false)]
public void AddCustomer(bool isCustomerValid)
{
//arrange
//NOTE!!! create the mocks with MockBehavior.Strict
//that way the test will fail if a call is made w/o setup
const long testCompanyId = 100;
var testCompany = new Company{ Id = testCompanyId };
companyRepository.Setup(r => r.GetById(testCompanyId))
.Returns(testCompany);
var testCustomer = new Customer
{
Firstname = "firstName",
Surname = "surname",
Company = new Company { Id = testCompanyId }
};
customerValidatorMock.Setup(c => c.IsValid(It.Is<Customer>(c => c == testCustomer && c.Company == testCompany)).Returns(isCustomerValid);
if (isCustomerValid)
{
customerRepository.Setup( r => r.AddCustomer(testCustomer) ). Verifiable();
}
//act
var addCustomerResult = customerServiceSut.AddCustomer(testCustomer);
//assert
Assert.AreEqual(isCustomerValid, addCustomerResult);
cutomerRepository.VerifyAll();
}
The above test will test all the functionality of the service method, including if the company is fetched by id, and if the fetched one is used. Also, it will verify if the customer is added, if it is valid. The test will fail, if the customer is added if not valid (as the customerRepository is created with MockBehavior.Strict, and a setup will not be performed).