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.
Related
I have a generic Repository with the Unit of Work pattern setup to utilize the Specification Pattern which works great but now I am trying to Unit test it and it seems my setup isn't returning anything when specifying what to return.
Repository Snippet
internal class Repository<T> : IRepository<T> where T : BaseEntity
{
protected readonly ApplicationDbContext _context;
public Repository(ApplicationDbContext context)
{
_context = context;
}
public IEnumerable<T> Find(ISpecification<T> specification = null)
{
return ApplySpecification(specification);
}
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
}
}
}
Snippet of Specification
public class GetStocksForCurrentDaySpecification : BaseSpecification<Stock>
{
public GetStocksForCurrentDaySpecification() : base(x => x.DateInserted.Day == DateTime.Today.Day) { }
}
Snippet of me calling it
_unitOfWork.Repository<Stock>().Find(new GetStocksForCurrentDaySpecification());
This all works perfectly when running my code.
Here is my Unit Test where I do setup.
[Fact]
public void Job_Should_Execute()
{
var stockList = new List<Stock>();
stockList.Add(new Stock
{
Id = Guid.NewGuid(),
DateInserted = DateTime.Now,
Exchange = "ASX",
LongName = "Long Name",
MarketOpenPrice = 1.26M,
MarketPreviousClosePrice = 1.56M,
MarketPrice = 1.3M,
ShortName = "Short Name",
Symbol = "LGN"
});
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());
var unitOfWorkMock = new Mock<IUnitOfWork>();
unitOfWorkMock.Setup(m => m.Repository<Stock>()).Returns(stockRepositoryMock.Object).Verifiable();
var job = new YahooStockMarketJob(new HttpClient(), unitOfWorkMock.Object, new EventPublisher(_listeners), _configuration);
job.Execute();
unitOfWorkMock.Verify();
}
When debugging, the following line returns an empty array instead of an array with one item it.
// Returns empty array
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());
In your mock object you are setting up the Find method with a specific instance of GetStocksForCurrentDaySpecification. During your test you are passing a different instance of GetStocksForCurrentDaySpecification and since those are not the same it won't use that setup.
If you want your setup to work with your test you either need to use the same instance or allow any instance of the object by using It.IsAny<T>.
E.g.
// Returns empty array
var stockRepositoryMock = new Mock<IRepository<Stock>>();
stockRepositoryMock
.Setup(m => m.Find(It.IsAny<GetStocksForCurrentDaySpecification>()))
.Returns(stockList.ToArray());
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 used test as below. I have one big method for initialize whole dbcontext (it is larger than pasted below, it is similar, but with more models and acces to each dbsets for MoQ Verify) something like fake db. Next I inject it to service and call method that using it.
Is it correct way for testing services (that using dbcontext) with unit tests? And if it is not correct, what is good way for testing services like this (maybe only write test that connect to real db)?
My Test:
[Test]
public void ExampleServiceTest()
{
var mock = InitializeMockContext();
var service = new TagsService(mock.Object);
var result = service.GetTags(2);
var expectection = 2;
Assert.AreEqual(expectection, result.Id);
}
Method that create mocked DBContext:
public Mock<MyDBContext> InitializeMockContext()
{
var mock = new Mock<MyDBContext>();
var mockDataTags = new List<Tags> {
new Tags { Id = 1, Count = 3 },
new Tags { Id = 2, Count = 2} }.AsQueryable();
var mockSet = new Mock<DbSet<Tags>>();
mockSet.As<IQueryable<Tags>>().Setup(m => m.Provider).Returns(mockDataTags.Provider);
mockSet.As<IQueryable<Tags>>().Setup(m => m.Expression).Returns(mockDataTags.Expression);
mockSet.As<IQueryable<Tags>>().Setup(m => m.ElementType).Returns(mockDataTags.ElementType);
mockSet.As<IQueryable<Tags>>().Setup(m => m.GetEnumerator()).Returns(mockDataTags.GetEnumerator());
mock.Setup(x => x.Tags).Returns(mockSet.Object);
//I have more than just one model here
return mock;
}
MyService:
public class TagsService
{
private readonly MyDBContext _ctx;
public TagsService(MyDBContext ctx)
{
_ctx = ctx;
}
public Tags GetTags(int count)
{
using (var db = _ctx)
{
return db.Tags.First(x => x.Count == count);
}
}
}
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);
}
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