I'm trying to figure out how to do my first Mock with Moq. I'm new to mocking as well.
Lets say I have the following TDD test:
[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
// Arrange
var preAuthorizeRequest = new PreAuthorizeRequest();
// Act
var authorizeResponse = _dataProcessor.SendRequest(preAuthorizeRequest);
// Assert
Assert.IsNotNull(authorizeResponse);
}
The scenario for that test above is that if we send in an object instance that has no state, we should still get back a response object (it shouldn't blow up). So I guess in Mock and Stub terms I guess I want to test the behavior of the dataProcessor's SendRequest method in that it'll send back an instance of PreAuthorizeResponse....right?
Now here's the info on what these types are:
public interface IPaymentRequest
{
string SecurityToken { get; set; }
int RetailID { get; set; }
int ProcessorId { get; set; }
}
public class PreAuthorizeRequest : IPaymentRequest
{
public string SecurityToken { get; set; }
public int RetailID { get; set; }
public int ProcessorId { get; set; }
public PreAuthorizeTransaction Transaction { get; set; }
}
public IPaymentResponse SendRequest(IPaymentRequest request)
{
ITransaction transaction = PaymentUtilities.GetPaymentRequestTransactionType(request);
IPaymentResponse response = PaymentUtilities.GetPaymentResponseType(request);
var transactionType = PaymentUtilities.GetPaymentRequestTransactionTypeEnum(request);
var requestValidator = new PaymentRequestValidator();
requestValidator.ValidateRequest(request);
var requestIsValid = requestValidator.RequestIsValid;
if (!requestIsValid)
{
response = PaymentUtilities.BuildPaymentResponse(request, requestValidator, transaction, transactionType);
return response;
}
IAutoPaymentProcessor autoPaymentProcessor = CreateAutoPaymentProcessor(request);
var configValidator = new ConfigurationValidator(autoPaymentProcessor);
configValidator.ValidateConfigurationSettings();
bool settingsAreValid = configValidator.ConfigIsValid;
if (!settingsAreValid)
{
response = PaymentUtilities.BuildPaymentResponse(request, requestValidator, transaction, transactionType);
return response;
}
response = SetConfigSettings(request, response);
Document dataResponseDoc = SendRequest(request, response);
response.PaymentProcessorId = (int)Enums.PaymentProcessorType.Data;
response.ProviderAuthCode = dataResponseDoc != null ? dataResponseDoc.get("Response.authcode") : string.Empty;
response.ProviderReference = dataResponseDoc != null ? dataResponseDoc.get("Response.data_reference") : string.Empty;
return response;
}
So I don't see the need for a mock, in other words a verify call on the mock right? I think I just need a stub and to test whether I get an instance of PreAuthorizeResponse back. So I guess that's a stub with Moq right?
Well then how would I do this with Moq if I'm right about me only needing to work with a stub here?
I tried this but I feel this is wrong since I feel the SUT is my data processor which I believe you should not mock the object in test:
[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
// Arrange - setup data
var dataProcessorStub = new Mock<IPaymentProcessor>();
var preAuthorizeRequest = new PreAuthorizeRequest();
// Act
//setup - expectations
dataProcessorStub.Setup(p => p.SendRequest(It.IsAny<PreAuthorizeRequest>())).Returns(It.IsAny<PreAuthorizeResponse>());
// excercise
var preAuthorizeResponse = dataProcessorStub.Object.SendRequest(preAuthorizeRequest);
// Assert
Assert.IsInstanceOfType(preAuthorizeResponse, typeof(PreAuthorizeResponse));
}
No, you don't really want to be mocking the object you are trying to test. You should mock the dependencies of that object (e.g. the database object).
The dataProcessor is the Object under Test (also known as System under Test), and everything else are collaborators (dependencies of the SUT).
You are going to find it difficult to test this properly though, due to the number of hard dependencies that you have within the SendRequest method.
At the very least, you want to mock the PaymentRequestValidator so that when you send in a specific type of request, you can have the mock setup to say that it is not valid, and then handle that in the code, which in turn will cause the SendRequest method to return a response.
To achieve that though, you will need to refactor your code in order to pass a mocked instance of the request validator in. Also, probably quite a few of the other objects as well.
For example, you'll more than likely need to mock the PaymentUtilities object so that you can have the methods you use return Mock objects, which are themselves setup to return specific things for this test. Similarly the ConfigurationValidator - will it return a valid configuration when it is called from the test (probably a different test), or do you need to mock that as well?
This is heading well into the realms of dependency injection and inversion of control. I won't insult you are by providing links, but those subjects are well covered in literature both in print and on the web.
Looking at the code, it seems like you don't need to do any mocking if you are trying to test the SendRequest method. You need to mock the dependencies of what you are trying to test, not the object under test itself. So if your PaymentProcessor had any external dependencies required for the test you'd need to mock those.
The SendRequest method does take an interface which you can mock, but it's easier to just pass in a newly created PreAuthorizeRequest.
[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
// Arrange
var preAuthorizeRequest = new PreAuthorizeRequest();
// Act
var authorizeResponse = _dataProcessor.SendRequest(preAuthorizeRequest);
// Assert
Assert.IsNotNull(authorizeResponse);
}
Alternatively you can mock the request:
[TestMethod]
public void PreAuthorize_WithEmptyRequest_ReturnsNonNullResponse()
{
// Arrange
var request = new Mock<IPaymentRequest>();
// Act
var authorizeResponse = _dataProcessor.SendRequest(request);
// Assert
Assert.IsNotNull(authorizeResponse);
}
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);
}
My apologies in advanced for not knowing the technical name of this scenario. I am mocking for unit test and that is all fine. However on this section of code I have run into a scenario that exceeds my mocking knowledge. Basically I have MethodA that takes 3 parameters. One of the parameters is passed as another method's output.
When I step through the method passed as a parameter is executed
My difficulty is that the passed method is being executed BEFORE my mocked object. Now it seems like a simple solution...mock the second method as well...that is where my knowledge falls down. I don't know how to get the "second" method mock into the testing context.
My controller being tested (simplified of course):
public class OrderController : ApiController
{
public OrderController(IRepositoryK repositoryk)
{}
public HttpResponseMessage NewOrder()
{
...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
using (var client = new HttpClient())
{...make call to Google API...}
}
}
My test:
[TestMethod]
public void AddOrder_CorrectResponse()
{
private Mock<IRepositoryK> _repK = new Mock<IRepositoryK>();
_repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns("Yippe");
//of course I've left out all the controller buildup and execution stuff.
}
So I really have no desire to dive into MethodB but it seems to be doing it anyway. What am I doing wrong?
TIA
Thank you for your responses. I understand completely what you are saying. I'm trying to get some testing coverage in place before refactoring. So is there no way of keeping methodB from executing and just let my repositoryK mock just return what I've specified in the setup.
Your code is not easy to test, because it has hard dependency on HttpClient. You have nicely separated repository implementation, but if you want to easily test the code you should also separate code which calls Google API. The idea is to have something like this:
// Add interfece for accessing Google API
public interface IGoogleClient
{
string GetData(string data);
}
// Then implementation is identical to MethodB implementation:
public class GoogleClient : IGoogleClient
{
public string GetData(string data)
{
using (var client = new HttpClient())
{
//...make call to Google API...
}
}
}
// Your controller should look like this:
public class OrderController : ApiController
{
private readonly IRepositoryK repositoryk;
private readonly IGoogleClient googleClient;
public OrderController(IRepositoryK repositoryk, IGoogleClient googleClient)
{
this.googleClient = googleClient;
this.repositoryk = repositoryk;
}
public HttpResponseMessage NewOrder()
{
//...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
return googleClient.GetData(data);
}
}
If you have such setup you can easily mock both IRepositoryK and IGoogleClient:
Mock<IRepositoryK> repK = new Mock<IRepositoryK>();
Mock<IGoogleClient> googleClient = new Mock<IGoogleClient>();
repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("Yippe");
googleClient.Setup(It.IsAny<string>()).Returns("something");
var controller = new OrderController(repK.Object, googleClient.Object);
// Test what you want on controller object
However, if you want to keep your code tightly coupled you can mock the call to MethodB with small changes.
First, you need to make method MethodB virtual, so it could be overridden in mock:
public virtual string MethodB(string data)
{
// your code
}
Then in your test instead of instantiating controller, instantiate and use mock of your controller:
var repK = new Mock<IRepositoryK>();
// create mock and pass the same constructor parameters as actual object
var controllerMock = new Mock<OrderController>(repK.Object);
controllerMock.CallBase = true;
// mock MethodB method:
controllerMock.Setup(x => x.MethodB(It.IsAny<string>())).Returns("data");
// call the method on mock object
// instead of calling MethodB you will get a mocked result
var result = controllerMock.Object.NewOrder();
I am trying to mock (using Moq) a class set a return object on a class that only exposes two properties.
In my limited Moq experience I would normally use a Setup() lamda to define the method call and then Returns() to spit back the desired output.
What I am falling down on here is the Setup(). There isn't a "method" to call as the constructor does the work, populates the two properties and then returns.
My class that I want to mock...obviously dummied down:
public class CarResponse
{
public IMetaModel meta { get; set; }
public List<ICarModel> cars { get; set; }
public CarResponse(Common.Models.Car car)
{
this.cars = new List<ICarModel>();
}
}
My feeble attempt at mocking:
private Mock<CarResponse> _carResponse = new Mock<CarResponse>(MockBehavior.Strict);
_carResponse.Setup( ????? ).Returns(new CarResponse() { meta = new MetaModelV2(), cars = foo });
To further clarify...here is the code I am trying to write a unit test for:
public HttpResponseMessage AddPickup()
{
//....code removed for brevity....
//this repository is mocked and returns the object exactly as I want it
var car = carRepository.GetCar(carId);
if (!errorInfo.Any()) //This check is bogus it never gets sets
{
RequestHelper rqh = new RequestHelper();
response = rqh.CreateResponse(Request, HttpStatusCode.OK, new CarResponse(car));
}
My unit test:
[TestMethod]
public void AddValidPickupCorrectResponse()
{
//arrange
//...lots of code here left off for setting up http context etc
//act---
var response = controller.AddPickup();
//assert
}
If I were to use a precanned object as suggested how would I "hook" it to the code under test. For example I write a unit test that uses my pre-canned object instead of a Moq but how do I get that pre-canned object to be used by the SUT?
There are few problems which can get in the way of properly unit testing the above code:
new-ing up the response helper
new-ing up the CarResponseObject
In essence, unless a class in real POCO (i.e. only data with public setters and getters), using "new" is a killer for unit testing. I.e. it is not a unit test (test the unit/method in isolation). It tests the behavior of the CarResponse ctor, as well as the working of RequestHelper.
Consider the following changes:
Inject the RequestHelper (so you can mock the CreateResponse method)
Use and inject some mapping factory of sort, which can create CarResponseObjects from Car.
Consider CarResponse to implement something like IResponse, so your RequestHelper, or factory, can return interfaces.
With all of the above, your test will look like (pseudo code, not complete):
//arrange
//....
var carInDB = new Car();
_repoMock.Setup(...).Returns(car);
var carResponse = Mock.Of<IResponse>();
_mapperMock.Setup(m=>m.CreateResponse(car).Returns(carResponse);
var responseFromHelper = new WhateverResponseIsNeeded(); //(or create a new mock IResponse - note! new mock, different than car response
_helperMock.Setup(_controller.Request, HttpStatusCode.OK, carResponse).Returns(responseFromHelper);
//act
var response = _controller.AddPickup();
//assert
response.Should().Be.SameInstanceAs(responseFromHelper)
You can use SetupGet and SetupSet to mock properties. However, I don't think you can mock concrete classes.
If you are dealing with a value type you might find it easier to not bother mocking and just used a pre-canned object.
I have a Transfer class, simplified it looks like this:
public class Transfer
{
public virtual IFileConnection source { get; set; }
public virtual IFileConnection destination { get; set; }
public virtual void GetFile(IFileConnection connection,
string remoteFilename, string localFilename)
{
connection.Get(remoteFilename, localFilename);
}
public virtual void PutFile(IFileConnection connection,
string localFilename, string remoteFilename)
{
connection.Get(remoteFilename, localFilename);
}
public virtual void TransferFiles(string sourceName, string destName)
{
source = internalConfig.GetFileConnection("source");
destination = internalConfig.GetFileConnection("destination");
var tempName = Path.GetTempFileName();
GetFile(source, sourceName, tempName);
PutFile(destination, tempName, destName);
}
}
The simplified version of the IFileConnection interface looks like this:
public interface IFileConnection
{
void Get(string remoteFileName, string localFileName);
void Put(string localFileName, string remoteFileName);
}
The real class is supposed to handle a System.IO.IOException that is thrown when the IFileConnection concrete classes loses connectivity with the remote, sending out emails and what not.
I would like to use Moq to create a Transfer class, and use it as my concrete Transfer class in all properties and methods, except when the GetFile method is invoked - then I want it to throw a System.IO.IOException and make sure the Transfer class handles it properly.
Am I using the right tool for the job? Am I going about this the right way? And how would I write the setup for that unit test for NUnit?
Here's how you can mock your FileConnection
Mock<IFileConnection> fileConnection = new Mock<IFileConnection>(
MockBehavior.Strict);
fileConnection.Setup(item => item.Get(It.IsAny<string>,It.IsAny<string>))
.Throws(new IOException());
Then instantiate your Transfer class and use the mock in your method call
Transfer transfer = new Transfer();
transfer.GetFile(fileConnection.Object, someRemoteFilename, someLocalFileName);
Update:
First of all you have to mock your dependencies only, not the class you are testing(Transfer class in this case). Stating those dependencies in your constructor make it easy to see what services your class needs to work. It also makes it possible to replace them with fakes when you are writing your unit tests. At the moment it's impossible to replace those properties with fakes.
Since you are setting those properties using another dependency, I would write it like this:
public class Transfer
{
public Transfer(IInternalConfig internalConfig)
{
source = internalConfig.GetFileConnection("source");
destination = internalConfig.GetFileConnection("destination");
}
//you should consider making these private or protected fields
public virtual IFileConnection source { get; set; }
public virtual IFileConnection destination { get; set; }
public virtual void GetFile(IFileConnection connection,
string remoteFilename, string localFilename)
{
connection.Get(remoteFilename, localFilename);
}
public virtual void PutFile(IFileConnection connection,
string localFilename, string remoteFilename)
{
connection.Get(remoteFilename, localFilename);
}
public virtual void TransferFiles(string sourceName, string destName)
{
var tempName = Path.GetTempFileName();
GetFile(source, sourceName, tempName);
PutFile(destination, tempName, destName);
}
}
This way you can mock internalConfig and make it return IFileConnection mocks that does what you want.
I think this is what you want, I already tested this code and works
The tools used are: (all these tools can be downloaded as Nuget packages)
http://fluentassertions.codeplex.com/
http://autofixture.codeplex.com/
http://code.google.com/p/moq/
https://nuget.org/packages/AutoFixture.AutoMoq
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var myInterface = fixture.Freeze<Mock<IFileConnection>>();
var sut = fixture.CreateAnonymous<Transfer>();
myInterface.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
.Throws<System.IO.IOException>();
sut.Invoking(x =>
x.TransferFiles(
myInterface.Object,
It.IsAny<string>(),
It.IsAny<string>()
))
.ShouldThrow<System.IO.IOException>();
Edited:
Let me explain:
When you write a test, you must know exactly what you want to test, this is called: "subject under test (SUT)", if my understanding is correctly, in this case your SUT is: Transfer
So with this in mind, you should not mock your SUT, if you substitute your SUT, then you wouldn't be actually testing the real code
When your SUT has external dependencies (very common) then you need to substitute them in order to test in isolation your SUT. When I say substitute I'm referring to use a mock, dummy, mock, etc depending on your needs
In this case your external dependency is IFileConnection so you need to create mock for this dependency and configure it to throw the exception, then just call your SUT real method and assert your method handles the exception as expected
var fixture = new Fixture().Customize(new AutoMoqCustomization());: This linie initializes a new Fixture object (Autofixture library), this object is used to create SUT's without having to explicitly have to worry about the constructor parameters, since they are created automatically or mocked, in this case using Moq
var myInterface = fixture.Freeze<Mock<IFileConnection>>();: This freezes the IFileConnection dependency. Freeze means that Autofixture will use always this dependency when asked, like a singleton for simplicity. But the interesting part is that we are creating a Mock of this dependency, you can use all the Moq methods, since this is a simple Moq object
var sut = fixture.CreateAnonymous<Transfer>();: Here AutoFixture is creating the SUT for us
myInterface.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>())).Throws<System.IO.IOException>(); Here you are configuring the dependency to throw an exception whenever the Get method is called, the rest of the methods from this interface are not being configured, therefore if you try to access them you will get an unexpected exception
sut.Invoking(x => x.TransferFiles(myInterface.Object, It.IsAny<string>(), It.IsAny<string>())).ShouldThrow<System.IO.IOException>();: And finally, the time to test your SUT, this line uses the FluenAssertions library, and it just calls the TransferFiles real method from the SUT and as parameters it receives the mocked IFileConnection so whenever you call the IFileConnection.Get in the normal flow of your SUT TransferFiles method, the mocked object will be invoking throwing the configured exception and this is the time to assert that your SUT is handling correctly the exception, in this case, I am just assuring that the exception was thrown by using the ShouldThrow<System.IO.IOException>() (from the FluentAssertions library)
References recommended:
http://martinfowler.com/articles/mocksArentStubs.html
http://misko.hevery.com/code-reviewers-guide/
http://misko.hevery.com/presentations/
http://www.youtube.com/watch?v=wEhu57pih5w&feature=player_embedded
http://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=player_embedded
This is how I managed to do what I was trying to do:
[Test]
public void TransferHandlesDisconnect()
{
// ... set up config here
var methodTester = new Mock<Transfer>(configInfo);
methodTester.CallBase = true;
methodTester
.Setup(m =>
m.GetFile(
It.IsAny<IFileConnection>(),
It.IsAny<string>(),
It.IsAny<string>()
))
.Throws<System.IO.IOException>();
methodTester.Object.TransferFiles("foo1", "foo2");
Assert.IsTrue(methodTester.Object.Status == TransferStatus.TransferInterrupted);
}
If there is a problem with this method, I would like to know; the other answers suggest I am doing this wrong, but this was exactly what I was trying to do.