I get very confused when I have to unit test a method which is calling multiple public methods of other classes. Here is the example
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SkillKindle.BLL;
using SkillKindle.BLL.ClassDetails;
using SkillKindle.BLL.SkClasses;
using SkillKindle.Domain.Models.SkClasses;
using SkillKindle.Infrastructure;
using SkillKindle.Web.Core.Infrastructure.ErrorHandling;
using SkillKindleWeb.Mappers;
using SkillKindleWeb.ViewModels.ClassDetails;
namespace SkillKindleWeb.Controllers
{
[CustomHandleError(ExceptionType = typeof (BusinessValidationException))]
public class ClassDetailsController : BaseController
{
private readonly ILogger _logger;
private readonly IMapperService _mapperService;
private readonly IAccessorFactory _accessorFactory;
private const int RegistrationId = 34;
private IClassDetailsAccessor ClassDetailsAccessor
{
get { return _accessorFactory.CreateClassDetailsAccessor(); }
}
private ISkClassAccessor SkClassAccessor
{
get { return _accessorFactory.CreateSkClassAccessor(); }
}
private IClassCreativeAccessor ClassCreativeAccessor
{
get { return _accessorFactory.CreateClassCreativeAccessor(); }
}
public ClassDetailsController(ILogger logger, IMapperService mapperService,
IAccessorFactory accessorFactory)
{
_logger = logger;
_mapperService = mapperService;
_accessorFactory = accessorFactory;
}
public ViewResult Index(int classCreativeId)
{
var classCreative = ClassCreativeAccessor.GetClassCreative(classCreativeId);
if (classCreative == null)
{
throw new HttpException(404, "The url is not valid");
}
var batches = ClassCreativeAccessor.GetFutureBatches(classCreativeId);
IList<ClassTicket> tickets = new List<ClassTicket>();
IList<Venue> venues = new List<Venue>();
if (batches.Count > 0)
{
tickets =
ClassCreativeAccessor.GetTickets(
batches.Select(batch => batch.ClassScheduleId).Distinct().ToArray());
venues = SkClassAccessor.GetVenues(batches.Select(batch => batch.VenueId).Distinct().ToArray());
}
var classDetailsViewModel = _mapperService.ClassCreativeToClassDetailsViewModel(classCreative);
var batchViewModels = _mapperService.BatchToClassDetailsBatchViewModel(batches).ToList();
var ticketViewModels = _mapperService.ClassTicketToClassDetailsTicketViewModel(tickets).ToList();
var venueViewModels = _mapperService.VenueToClassDetailsVenueViewModel(venues).ToList();
var indexViewModel = new IndexViewModel()
{
Batches = batchViewModels,
Tickets = ticketViewModels,
ClassDetails = classDetailsViewModel,
Venues = venueViewModels
};
return View(indexViewModel);
}
}
}
Here Index method is dependent on mapperService, SkClassAccessor, ClassDetailsAccessor,
ClassCreativeAccessor public methods. I have unit tested those public method separately. Now when it comes to test Index method, I need to check the correctness of indexViewModel. Here are couple of options with me.
Option 1. Mock the public methods of dependent classes to return fake objects and check IndexViewModel has those fake object. I am not sure if this is a real test. Also it does not test that I am passing the write arguments to these mock public methods.
Option 2. Don't mock the public methods of dependent classes but fake the dependencies of dependent classes. e.g. Fake the list of tickets ClassCreativeAccessor.GetTickets would operate on. This approach would verify that I passing the right argument to dependent public methods. But here I would be testing public methods again
I am not sure which approach is correct. Appreciate you help.
I am not sure if this is a real test.
This is a unit test as it should be. Don't mix it up with integration test.
Also it does not test that I am passing the write arguments to these
mock public methods.
When you are mocking dependencies (first option) you always can verify that methods was called with appropriate parameters. E.g. with Moq:
mock.Verify(foo => foo.Execute("ping"));
will check if method Execute of dependency foo was called with parameter "ping". Same way you can verify your ClassCreativeAccessor was called with appropriate parameters:
int classCreativeId = 42;
List<Batch> batches = new List<Batch>();
creativeAccessorMock.Setup(ca => ca.GetFutureBatches(classCreativeId))
.Returns(batches);
...
Related
I'm pretty new in .NET and I have to mock GetCustomerDetailsAsync endpoint using a local json file in order to get the file results and create a way to enable and disable the mocking mechanism. Here is the handler where I have to implement the logic
public class GetCustomerDetailsQueryHandler : IRequestHandler<GetCustomerDetailsQuery, CustomerInsertionModel>
{
private readonly ICustomerApiClient _customerApiClient;
private readonly IAccountApiClientGraphQl _accountApiClientGraphQl;
private readonly IMapper _mapper;
private readonly IMediator _mediator;
private readonly IOptions<CommonFeaturesOptions> _commonFeaturesOptions;
public GetCustomerDetailsQueryHandler(ICustomerApiClient customerApiClient,
IAccountApiClientGraphQl accountApiClientGraphQl,
IMediator mediator,
IMapper mapper,
IOptions<CommonFeaturesOptions> commonFeaturesOptions)
{
_customerApiClient = customerApiClient ?? throw new ArgumentNullException(nameof(customerApiClient));
_accountApiClientGraphQl = accountApiClientGraphQl ?? throw new ArgumentNullException(nameof(accountApiClientGraphQl));
_mediator = mediator;
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
_commonFeaturesOptions = commonFeaturesOptions ?? throw new ArgumentNullException(nameof(commonFeaturesOptions));
}
public async Task<CustomerInsertionModel> Handle(GetCustomerDetailsQuery request, CancellationToken cancellationToken)
{
//if(!EnablePostfixations){
//var customerApiResponse = (await _customerApiClient.GetCustomerDetailsAsync(_mapper.Map<GetCustomerDetailsRequest>(request)))
// .CustomerDetails.FirstOrDefault();
//}
//else
//{
//var response = await _customerApiClient.GetCustomerDetailsAsync(
// _mapper.Map<GetCustomerDetailsRequest>((request, _commonFeaturesOptions.Value)));
var customerApiResponse = (await _customerApiClient.GetCustomerDetailsAsync(_mapper.Map<GetCustomerDetailsRequest>(request)))
.CustomerDetails.FirstOrDefault();
if (customerApiResponse is null)
{
return new CustomerInsertionModel((false, string.Empty))
.MarkCustomerAsNotFound();
}
var customer = new CustomerInsertionModel(customerApiResponse.Cif,
customerApiResponse.CnpCui,
customerApiResponse.Category,
customerApiResponse.Insolvency,
request.AddInsolvency,
request.CloseCustomerCategories.ToList());
return customer
}
}
commented lines are just for guidence (what to do, inject an IOptions with a boolean that decide when to enable and disable the mocking mechanism )
plus I wanna know where should I have to deserialize the file(in handler or outside of it?)
public class DeserializeFromFileAsync
{
public class PostfixationsFile
{
public string Customer_no { get; set; }
public string First_name { get; set; }
public string Last_name { get; set; }
public string Customer_type { get; set; }
public string Adress_line { get; set; }
public int Cnp { get; set; }
public string Customer_category { get; set; }
public int Open_branch { get; set; }
public string Branch_name { get; set; }
public string Insolventa { get; set; }
}
public class Program
{
public static async Task Main()
{
string fileName = #"FullPath";
using FileStream openStream = File.OpenRead(fileName);
PostfixationsFile weatherForecast = await JsonSerializer.DeserializeAsync<PostfixationsFile>(openStream);
}
}
}
and this is the json file.
[
{ "customer_no": "03242524",
"first_name": "Prenume",
"last_name": "Nume",
"customer_type": "PF",'
"adress_line": " Str. FN Nr. Bl. Sc. Et. Ap. Sect. Loc. Jud. ",
"cnp": "1970907336523",
"customer_category": "PF_ONLINE",
"open_branch": "213",
"branch_name": "SUCURSALA DEJ",
"insolventa": "NU"
},
{ "customer_no": "03242524",
"first_name": "Prenume",
"last_name": "Nume",
"customer_type": "PF",'
"adress_line": " Str. FN Nr. Bl. Sc. Et. Ap. Sect. Loc. Jud. ",
"cnp": "1970907336523_J77",
"customer_category": "PF_ONLINE",
"open_branch": "213",
"branch_name": "SUCURSALA DEJ",
"insolventa": "NU"
}
]
Sorry for this messy message but is first time when I ask something here.
I wasn't able to build your code as it has a lot of dependencies which I'd need to make all sorts of assumptions about - you may want to read about creating a minimal, reproducible example.
However, I should be able to help you to understand how to use mocks. The first thing to know about mocks is that they should only be used in unit tests, not in your production code. So you wouldn't want to pass a flag into your actual handler to tell it whether or not to run in "mock" mode. Instead, you can create an instance of a mock in your unit test and then inject the mock into the code you're testing, so that your unit test can concentrate on the behaviour of the code you're testing, rather than the behaviour of any external code / web service / database etc that it is dependent on.
Imagine this is the class you want to test (equivalent of your GetCustomerDetailsQueryHandler).
public class MyHandler
{
private readonly IThingToMock thingToMock;
public MyHandler(IThingToMock thingToMock)
{
this.thingToMock = thingToMock;
}
public string MethodToTest(int id)
{
var request = new RequestModel { Id = id };
var response = this.thingToMock.GetInformation(request);
return response.Foo;
}
public async Task<string> MethodToTestAsync(int id)
{
var request = new RequestModel { Id = id };
var response = await this.thingToMock.GetInformationAsync(request).ConfigureAwait(false);
return response.Foo;
}
}
This is dependent on IThingToMock (equivalent of your ICustomerApiClient), which looks like this:
public interface IThingToMock
{
ResponseModel GetInformation(RequestModel request);
Task<ResponseModel> GetInformationAsync(RequestModel request);
}
And IThingToMock's request and response models look like this (I've deliberately kept them really simple):
public class RequestModel
{
public int Id { get; set; }
}
public class ResponseModel
{
public string Foo { get; set; }
}
Before you can start mocking, you need to add a unit test project to your solution (in Visual Studio's new project wizard, choose the template for a xUnit, nUnit or MSTest unit test project - which one you use is a matter of personal preference, I'm using xUnit for this answer).
Next, add a mocking NuGet package to your test project and add the appropriate using directive to your unit tests, e.g. using Moq;. I'm using Moq here, but again, other mocking packages are available, and it's up to you which one you want to use.
Now you can write a unit test, like this:
[Fact]
public void MethodToTest_AnyRequest_ReturnsExpectedResponse()
{
// Arrange
var mockThing = new Mock<IThingToMock>();
var expectedFoo = "Bar";
mockThing.Setup(m => m.GetInformation(It.IsAny<RequestModel>()))
.Returns(new ResponseModel { Foo = expectedFoo });
var handler = new MyHandler(mockThing.Object);
// Act
var actualFoo = handler.MethodToTest(1);
// Assert
Assert.Equal(expectedFoo, actualFoo);
}
Let's break this down. First, we create an instance of Mock<IThingToMock>. This has an Object property, which is an implementation of IThingToMock with all its methods and properties, except that by default the methods do nothing and any members with a return value return the default value for their return type (usually null).
Next, we use the Setup method to make our mock behave in the way we want. In this example, we're saying that its GetInformation method should always return a particular ResponseModel regardless of the properties of the RequestModel which were passed to it. I'm telling it to return a hard-coded value here, but you could tell the mock to return the data deserialized from your JSON file instead.
And then at the end of the Arrange step, we're injecting the mocked IThingToMock into the constructor of the MyHandler class, which is the class we want to test the behaviour of.
To control the behaviour of an asynchronous method, set up the mock using the ReturnsAsync method instead of Returns, for example:
[Fact]
public async Task MethodToTestAsync_AnyRequest_ReturnsExpectedResponse()
{
// Arrange
var mockThing = new Mock<IThingToMock>();
var expectedFoo = "Bar";
mockThing.Setup(m => m.GetInformationAsync(It.IsAny<RequestModel>()))
.ReturnsAsync(new ResponseModel { Foo = expectedFoo });
var handler = new MyHandler(mockThing.Object);
// Act
var actualFoo = await handler.MethodToTestAsync(1);
// Assert
Assert.Equal(expectedFoo, actualFoo);
}
Hopefully these examples give you sufficient insight into how mocks are used in unit tests to be able to apply the principles to your own situation. You may also want to read How YOU can Learn Mock testing in .NET Core and C# with Moq, which provides more examples of how to use Moq, this time with nUnit rather than xUnit, as well as some good practice around unit testing generally. And of course, be sure to consult the documentation for whichever mocking package you're using.
Happy mocking!
I'm having a difficult time trying to understand how to appropriately return mocked data from a simulated database call in a unit test.
Here's an example method I want to unit test (GetBuildings):
public class BuildingService : IBuildingService {
public IQueryable<Building> GetBuildings(int propertyId)
{
IQueryable<Building> buildings;
// Execution path for potential exception thrown
// if (...) throw new SpecialException();
// Another execution path...
// if (...) ...
using (var context = DataContext.Instance())
{
var Params = new List<SqlParameter>
{
new SqlParameter("#PropertyId", propertyId)
};
// I need to return mocked data here...
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
So GetBuildings calls a stored procedure.
So I need to mock the DataContext, that of which I can override and set a testable instance. So what happens here is, in the above example DataContext.Instance() does return the mocked object.
[TestFixture]
public class BuildingServiceTests
{
private Mock<IDataContext> _mockDataContext;
[SetUp]
public void Setup() {
_mockDataContext = new Mock<IDataContext>();
}
[TearDown]
public void TearDown() {
...
}
[Test]
public void SomeTestName() {
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
DataContext.SetTestableInstance(_mockDataContext.Object);
var builings = BuildingService.GetBuildings(1, 1);
// Assert...
}
Please ignore some of the parameters, like propertyId. I've stripped those out and simplified this all. I simply can't get the ExecuteQuery method to return any data.
All other simple peta-poco type methods I can mock without issue (i.e. Get, Insert, Delete).
Update
DataContext.Instance returns the active instance of the DataContext class, if exists, and if not exists, returns a new one. So the method of test under question returns the mocked instance.
Do not mock DataContext. Because mocking DataContext will produce tests tightly coupled to the implementation details of DataContext. And you will be forced to change tests for every change in the code even behavior will remain same.
Instead introduce a "DataService" interface and mock it in the tests for BuildingService.
public interface IDataService
{
IEnumerable<Building> GetBuildings(int propertyId)
}
Then, you can tests implementation of IDataService agains real database as part of integration tests or tests it agains database in memory.
If you can test with "InMemory" database (EF Core or Sqlite) - then even better -> write tests for BuildingService against actual implementation of DataContext.
In tests you should mock only external resources (web service, file system or database) or only resources which makes tests slow.
Not mocking other dependencies will save you time and give freedom while you refactoring your codebase.
After update:
Based on the updated question, where BuildingService have some execution path - you can still testing BuildingService and abstract data related logic to the IDataService.
For example below is BuildingService class
public class BuildingService
{
private readonly IDataService _dataService;
public BuildingService(IDataService dataService)
{
_dataService = dataService;
}
public IEnumerable<Building> GetBuildings(int propertyId)
{
if (propertyId < 0)
{
throw new ArgumentException("Negative id not allowed");
}
if (propertyId == 0)
{
return Enumerable.Empty<Building>();
}
return _myDataService.GetBuildingsOfProperty(int propertyId);
}
}
In tests you will create a mock for IDataService and pass it to the constructor of BuildingService
var fakeDataService = new Mock<IDataContext>();
var serviceUnderTest = new BuildingService(fakeDataService);
Then you will have tests for:
"Should throw exception when property Id is negative"
"Should return empty collection when property Id equals zero"
"Should return collection of expected buildings when valid property Id is given"
For last test case you will mock IDataService to return expected building only when correct propertyId is given to _dataService.GetBuildingsOfProperty method
In order for the mock to return data is needs to be set up to behave as expected given a provided input.
currently in the method under test it is being called like this
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
Yet in the test the mock context is being setup like
_mockDataContext.Setup(r =>
r.ExecuteQuery<Building>(CommandType.StoredProcedure, "someSproc"))
.Returns(new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable());
Note what the mock is told to expect as parameters.
The mock will only behave as expected when provided with those parameters. Otherwise it will return null.
Consider the following example of how the test can be exercised based on the code provided in the original question.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
DataContext.SetTestableInstance(_mockDataContext.Object);
var subject = new BuildingService();
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
That said, the current design of the system under test is tightly coupled to a static dependency which is a code smell and makes the current design follow some bad practices.
The static DataContext which is currently being used as a factory should be refactored as such,
public interface IDataContextFactory {
IDataContext CreateInstance();
}
and explicitly injected into dependent classes instead of calling the static factory method
public class BuildingService : IBuildingService {
private readonly IDataContextFactory factory;
public BuildingService(IDataContextFactory factory) {
this.factory = factory
}
public IQueryable<Building> GetBuildings(int propertyId) {
IQueryable<Building> buildings;
using (var context = factory.CreateInstance()) {
var Params = new List<SqlParameter> {
new SqlParameter("#PropertyId", propertyId)
};
buildings = context
.ExecuteQuery<Building>(System.Data.CommandType.StoredProcedure, "dbo.Building_List", Params.ToArray<object>())
.AsQueryable();
}
return buildings;
}
}
This will allow for a proper mock to be created in injected into the subject under test without using a static workaround hack.
[Test]
public void SomeTestName() {
//Arrange
var expected = new List<Building>() { new Building() { BuildingId = 1, Title = "1" }}.AsQueryable();
_mockDataContext
.Setup(_ => _.ExecuteQuery<Building>(CommandType.StoredProcedure, It.IsAny<string>(), It.IsAny<object[]>()))
.Returns(expected);
var factoryMock = new Mock<IDataContextFactory>();
factoryMock
.Setup(_ => _.CreateInstance())
.Returns(_mockDataContext.Object);
var subject = new BuildingService(factoryMock.Object);
//Act
var actual = subject.GetBuildings(1);
// Assert...
CollectionAssert.AreEquivalent(expected, actual);
}
I am a new guy in this Moq community.
I am wondering is there any way to put an Inheritance object of A (Mock) to a list of Mock interface A?
For example, assume we have
Class ClientA :IMyClient{...} //has override virtual codes
Class ClientB :IMyClient{...}
and
List<Mock<IMyClient>> mockClients = new List<Mock<IMyClient>>();
Is there anyway that I can do something like this:
var mockClientA = new Mock<ClientA>();
mockClients.Add(mockClientA);
I might not be on the right track. Need some help. Thanks.
=================================
Setup
// setup everyone to Free
actualManager.Status = Status.Free;
foreach (var mock in mockClients) {
mock.Object.Status = Status.Free;
actualManager.AddClient(mock.Object);
}
Test
Assert.AreEqual(Status.Free, actualManager.Status); // pass
var firstClient = mockClients.First();
IMyClient actualFirstClient = SetClientToTriggerOutsideCallbacks(firstClient);
firstClient.Status = Status.Busy;
// busy, since the first client is busy now.
Assert.AreEqual(Status.Busy, actualManager.Status); //pass
SessionSwitchEventArgs e = new SessionSwitchEventArgs(SessionSwitchReason.SessionLock);
actualManager.SystemEvents_SessionSwitch(null, e);
Assert.AreEqual(Status.Away, actualManager.Status); //not pass
I was trying to check influence of status changes on different clients, so I was trying to use a list to store all the clients.
The problem is: actualManager.SystemEvents_SessionSwitch(null, e); doesn't work correctly if the first client is not in type of ClientA.
First of all - why do we need mocks and stubs? Because our SUT (System Under Test, the object which you are testing) often has some dependencies. We cannot use real dependencies which we have in production code, because we will not be able to tell the reason why test is passing or failing. It might be error in SUT or in dependency. So we should provide something instead of real dependency which will be reliable. I.e. it should not produce any unexpected errors no matter how you change implementation of real dependencies. That's why we use stubs and mocks.
But what's the difference between them? Stubs are used in tests which do state verification. I.e. when you after exercising SUT verify state of SUT and (sometime) stub. Stub can be very simple. You can just implement dependency interface and use auto-properties without any logic inside. It's enough for you to setup some value, SUT will read/write something into stub. At the end you will check state. You will not check what operations were performed.
Behavior verification is very different. It focuses on interaction between SUT and dependencies. We setup some expectations for mock object. It's not same as setting up some properties with fake data. With mock you setup the fact that property or method should be called, and correct parameters should be passed. With stub you don't check whether it was called. You just make call possible and check state at the end.
So.. what you are doing here is state verification with mocks. Which is not how mocks supposed to be used. I.e. you setup status of clients and then check state of manager. Instead of using Moq following simple implementation completely satisfies your needs:
public class ClientStub : IMyClient
{
public Status Status { get; set; }
// some other members here
}
You can set status. Manager can read it. You can check manager's state. If you are going to use mocks, you should use behavior verification (otherwise it's just overkill). It's hard to tell what is the purpose of your manager class and how it checks status of clients. If you'll add this information I'll add some behavior verification test for your manager.
And regarding your question about putting mocks of different types into list - you cannot do that (well, only if you have list of objects). And it makes no sense. If some SUT expects list of dependencies, then you should put mock objects (accessible via Object property of mock) into that list. That's the difference between Moq and RhinoMocks.
Thank you, #SergeyBerezovskiy. I was not even in a right direction. Thank you for the ref link.
I rewrote the example of the link in C# version and tested. I think it help me understand Mock a lot. Please let me know if I made anything bad in here. Thanks.
WareHouse.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test {
public class WareHouse {
private Dictionary<string, int> wareHouseRepo = new Dictionary<string, int>();
public void Add(string location, int number) {
//null add
if (wareHouseRepo.ContainsKey(location)) {
int inventory_Old = wareHouseRepo[location];
wareHouseRepo[location] = inventory_Old + number;
} else {
wareHouseRepo.Add(location, number);
}
}
public virtual bool FillIt(string location, int number) {
if (wareHouseRepo.ContainsKey(location)) {
int inventory = wareHouseRepo[location];
if(inventory >= number){
wareHouseRepo[location] = inventory - number;
return true;
}else{
return false;
}
} else {
return false;
}
}
}
public int GetInventory(string location) {
if (wareHouseRepo.ContainsKey(location)) {
return wareHouseRepo[location];
} else {
return 0;
}
}
}
Order.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test {
class Order {
private string location = "";
private int orderNum = 0;
private bool filled = true;
public Order(string loc, int num) {
this.location = loc;
this.orderNum = num;
}
public void Fill(WareHouse wh){
if (wh.FillIt(location, orderNum)) {
filled = true;
} else {
filled = false;
}
}
public bool isFilled() {
return filled;
}
}
}
TestWareHouse.cs
using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test {
[TestFixture]
class TestWareHouse {
private WareHouse warehouse = new WareHouse();
private static String TALISKER = "Talisker";
private static String HIGHLAND_PARK = "Highland Park";
[SetUp]
public void SetUp() {
//reset
warehouse = new WareHouse();
warehouse.Add(TALISKER, 50);
warehouse.Add(HIGHLAND_PARK, 25);
}
//regular testing
[Test]
public void testOrderIsFilledIfEnoughInWarehouse() {
Order order = new Order(TALISKER, 50);
order.Fill(warehouse);
Assert.True(order.isFilled());
Assert.AreEqual(0, warehouse.GetInventory(TALISKER));
}
[Test]
public void testOrderDoesNotRemoveIfNotEnough() {
Order order = new Order(TALISKER, 51);
order.Fill(warehouse);
Assert.False(order.isFilled());
Assert.AreEqual(50, warehouse.GetInventory(TALISKER));
}
//Now I am trying to do the things with Mock
[Test]
public void testOrderIsFilledIfEnoughInWarehouseMock() {
Order order = new Order(TALISKER, 50);
//-- Creating a fake ICustomerRepository object
var warehouseMock = new Mock<WareHouse>();
//warehouseMock
warehouseMock
.Setup(m => m.FillIt(TALISKER, 50))
.Returns(true);
order.Fill(warehouseMock.Object);
//-- Assert ----------------------
Assert.IsTrue(order.isFilled());
warehouseMock.Verify(x => x.FillIt(It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(1));
}
[Test]
public void testFillingDoesNotRemoveIfNotEnoughInStock() {
Order order = new Order(TALISKER, 51);
//-- Creating a fake ICustomerRepository object
var warehouseMock = new Mock<WareHouse>();
warehouseMock
.Setup(m => m.FillIt(It.IsAny<string>(), It.IsAny<int>()))
.Returns(false);
order.Fill(warehouseMock.Object);
//-- Assert ----------------------
Assert.IsFalse(order.isFilled());
warehouseMock.Verify(x => x.FillIt(It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(1));
}
}
}
I have a method CreateAccount to test. I am using Moq for the same.
Under CreateAccount method, there are multiple table insertion methods which belongs to two classes AccountRepository and BillingRepository
I have setup the Moq but don't know how to use multiple moq objects.
Below is some code snippet
Mock<AccountRepository> moq = new Mock<AccountRepository>();
Mock<BillingRepository> moqBill = new Mock<BillingRepository>();
moq.Setup(x => x.AddTable_1(new AddTable_1 { }));
moq.Setup(x => x.AddTable_2(new AddTable_2 { }));
moqBill.Setup(x => x.Table_3());
CreateAccount method takes four parameters and its under ApplicationService class
public class ApplicationService
{
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
obj_1.AddTable_1(objdata_1);
obj_1.AddTable_2(objdata_2);
obj_2.AddTable_3(objdata_3);
}
}
Please suggest some solution. How can these three methods will be skipped ?
Thanks in advance.
You have to provide some means to inject obj_1 and obj_2, since they seem to represent your instances of AccountRepository and BillingRepository, resp.
Typically, you might want to do this by using constructor injection. Extending the snippet you provided, this might look like this:
public class ApplicationService
{
private readonly AccountRepository _accountRepository;
private readonly BillingRepository _billingRepository;
public ApplicationService(AccountRepository accountRepository, BillingRepository billingRepository)
{
_accountRepository = accountRepository;
_billingRepository = billingRepository;
}
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
_accountRepository.AddTable_1(objdata_1);
_accountRepository.AddTable_2(objdata_2);
_billingRepository.AddTable_3(objdata_3);
}
}
Now you can inject your mocks into the class under test:
public void CreateAccount_WhenCalledLikeThis_DoesSomeCoolStuff()
{
var accountRepoMock = new Mock<AccountRepository>();
// set it up
var billingRepository = new Mock<BillingRepository>();
// set it up
var appService = new ApplicationService(accountRepoMock.Object, billingRepoMock.Objcet);
// More setup
// Act
var response = appService.CreateAccount(...);
// Assert on response and/or verify mocks
}
I have a controller that need to test. It has a method with the function inside.
public ActionResult GetZZ()
{
ApplyResponseHeaders();
var result = new MediaJsonResult();
using (var str = new StreamReader(Request.InputStream))
{
string inputData = str.ReadToEnd();
MyFunction(inputData, result);
}
return Json(result);
}
I just want to test the function MyFunction. This function is private. How can I do this. Test the entire method is not necessary, because the problems in the appointment of its values in Request.InputStream
Don't try to test private methods ever. These methods are not part of public API and cannot be invoked by caller. Your goal is to satisfy requirements for public API. It really doesn't matter if private method works as expected or not. From caller's point of view this method does not exist and does not have any value.
Instead you should test functionality, which is available via public API, GetZZ() method in your case. But you should mock external dependencies in order to test your controller in isolation with any test data you want.
So, here you have two options. First one is mocking HttpRequest which your controller depends on, and providing test data for input stream (you will have to do lot of work):
var httpRequest = new Mock<HttpRequestBase>();
var stream = new MemoryStream(Encoding.Default.GetBytes("Hello world"));
httpRequest.Setup(r => r.InputStream).Returns(stream);
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(c => c.Request).Returns(httpRequest.Object);
var controller = new HomeController();
var routeData = new RouteData();
controller.ControllerContext = // set mocked context
new ControllerContext(httpContext.Object, routeData, controller);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42)); // your assertions here
Another option - hiding this environment-related stuff under some abstraction, which can be easily mocked (of course, you should use better names):
public interface IFoo
{
string Bar();
}
This is a implementation, which uses current context request to get input data:
public class Foo : IFoo
{
public string Bar()
{
using (var str = new StreamReader(HttpContext.Current.Request.InputStream))
{
string inputData = str.ReadToEnd();
return inputData;
}
}
}
Make controller depend on this abstraction:
public class HomeController : Controller
{
private readonly IFoo _foo;
public HomeController(IFoo foo) // inject dependency
{
_foo = foo;
}
public ActionResult GetZZ()
{
ApplyResponseHeaders();
var result = new JsonResult();
MyFunction(_foo.Bar(), result); // use dependency
return result;
}
}
Now you can mock it without any problems:
var foo = new Mock<IFoo>();
foo.Setup(f => f.Bar()).Returns("Hello, TDD");
var controller = new HomeController(foo.Object);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42));
One easy way is to make the method public. If you can't (or don't want to), you could make the method protected instead of private, then subclass your controller in your test assembly and test it through the derived type.
Something like so:
public class TesterController : YourController
{
public new ActionResult MyFunction(string inputData, MediaJsonResult result)
{
return base.MyFunction(inputData, result);
}
}
You can mark the methods as internal instead of private and then add a InternalsVisibleTo("Path.To.Test.Project") in AssemblyInfo.cs of your controllers.
Not 100% sure agree about NEVER EVER test a private method in your code. Like most things, sometimes it makes sense and being pragmatic is often better then being dogmatic.