I am new to writing Unit Test in visual studio. In my web application i have following contents.
1> Interface
public interface IGettProxy
{
Task<List<CityDetails>> getCity();
Task<List<CountryDetails>> getCountry(int cityId);
}
2> Contracts (Implementation of Interface)
public async Task<List<CityDetails>> getCity()
{
try
{
_serviceUrl = String.Format("{0}/Search/getCityinfo", _serviceUrl);
string requestUri = _serviceUrl;
client = new HttpClient();
var response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
var Result = new JavaScriptSerializer().Deserialize<List<CityDetails>>(json);
return Result;
}
else
{
throw new Exception("Errorhandling message");
}
}
catch (Exception ex) { throw ex; }
}
public async Task<List<CountryDetails>> getCountry(int cityId)
{
try
{
_serviceUrl = String.Format("{0}/Search/getcountryinfo?cityId={1}", _serviceUrl, cityId);
string requestUri = _serviceUrl;
client = new HttpClient();
var response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
var Result = new JavaScriptSerializer().Deserialize<List<CountryDetails>>(json);
return Result;
}
else
{
throw new Exception("Errorhandling message");
}
}
catch (Exception ex) { throw ex; }
}
3> Controller
private IGettProxy igettProxy;
public GettController(IGettProxy gettProxy)
{
igettProxy = gettProxy;
}
/// <summary>
/// Invoked on Page Load
/// </summary>
/// <returns></returns>
public async Task<ActionResult> Getdet()
{
try
{
List<CityDetails> cityDetails = await igettProxy.getCity();
SearchModel viewModel = new SearchModel();
viewModel.cityDetail = cityDetails;
return View(viewModel);
}
catch (Exception ex) { throw ex; }
}
/// <summary>
/// Get Country list based on city information
/// </summary>
/// <param name="cityId"></param>
/// <returns></returns>
public async Task<JsonResult> getCountry (int cityId)
{
try
{
List<CountryDetails> CountryDetails = await iSearchProxy.getCountry(cityId);
return Json(CountryDetails,JsonRequestBehavior.AllowGet);
}
catch (Exception ex) { throw ex; }
}
I have different class libraries for data member.
For injection configuration i am using Unity method.
So in this view i have drop down to bind city, country values.
For this drop down binding i want to write unit test. Please help me with this detail. Thanks in advance.
My Test method
[TestMethod]
public void bookAppointment()
{
List<CityDetails> cityDetails = new List<CityDetails>();
cityDetails.Add(new CityDetails {ID=1,CityName="Delhi"});
// var mockproxy = new StubISearchProxy();
StubISearchProxy searchProxy = new StubISearchProxy();
searchProxy.GetCity = () => cityDetails;
SearchController searchController = new SearchController(searchProxy);
var str = searchController.getCity();
}
In DI Unity will resolve this interface implementation for you. In order to test this you'll have to create a fake class that implements your interface, and inject (on the constructor).
Something like:
public class FakeClass : IGettProxy {
public Task<List<CityDetails>> getCity(){
// here goes your fake implementation, to be injected on your controller.
}
// Remember to implement the other method
}
Then when you instantiate your controller you're going to pass this fake implementation of the interface (that what the constructor requires).
And now you can test it.
Related
I am trying to create different types of errors in an ASP.NET controller (which communicates with a service). Right now I am focusing on a ServiceNotFound error, but DbContextMock() always returns true. What is the correct way to do this?
(In OrdersController.cs)
public OrdersController(IOrdersService ordersService)
{
_ordersService = ordersService ?? throw new ArgumentNullException(nameof(ordersService));
}
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType((int)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> PutOrdersAsync()
{
try
{
await _ordersService.PutOrdersAsync();
return new StatusCodeResult(StatusCodes.Status204NoContent);
}
catch (ServiceException ex)
{
return StatusCode(
(int)ex.StatusCode,
Responses.ErrorResponse with { Message = ex.Message, Content = JsonConvert.SerializeObject(ex), RequestId = Request.HttpContext.Connection.Id }
);
}
catch (Exception ex)
{
return StatusCode(
StatusCodes.Status500InternalServerError,
Responses.ErrorResponse with { Message = ex.Message, Content = JsonConvert.SerializeObject(ex), RequestId = Request.HttpContext.Connection.Id }
);
}
}
(In Tests.cs)
...
var context = new DbContextMock();
...
var service = GetOrdersService(context.Object, _pdcClientFactory.Object);
...
await service.PutOrdersAsync();
I'm writing a unit test where I'm trying to partially mock a service. What I mean is I want one of the methods of the service to return a different mocked object and another method to behave as normal. This is the method I'm testing:
public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject
{
List<string> result;
try
{
var client = await this.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}
return result;
}
This is the method that I need to return a mocked object:
public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();
var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";
await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);
forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}
return forceClient;
}
And this is what I currently have in my unit test:
var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);
var mockService = new Mock<IForceDotComService>();
mockService.Setup(m => m.GetDeletedRecordIds<sf.Account>(It.IsAny<DateTime>()))
.Returns(async (DateTime d) => await this._service.GetDeletedRecordIds<sf.Account>(d));
mockService.Setup(m => m.GetForceClient())
.ReturnsAsync(mockForceClient.Object);
Currently, the test runs in GetDeletedRecordIds until it hits the call to the GetForceClient method. Then instead of returning the mocked ForceClient object, it actually tries to run the method which of course fails.
Thanks in advance for any help.
SOLUTION:
Here's how I solved my problem.
First, I created a service to return the ForceClient as follows:
public class ForceClientService : IForceClientService
{
private readonly ILogger _logger;
private readonly ISettingService _settingService;
public ForceClientService(
ILogger<ForceClientService> logger,
ISettingService settingService)
{
this._logger = logger;
this._settingService = settingService;
}
public async Task<IForceClient> GetForceClient()
{
ForceClient forceClient = null;
try
{
var auth = new AuthenticationClient();
var consumerKey = this._settingService.GetSetting("SalesForceConsumerKey");
var consumerSecret = this._settingService.GetSetting("SalesForceConsumerSecret");
var password = this._settingService.GetSetting("SalesForcePassword");
var securityToken = this._settingService.GetSetting("SalesForceSecurityToken");
var username = this._settingService.GetSetting("SalesForceUsername");
var tokenUrl = $"{this._settingService.GetSetting("SalesForceUrl")}/services/oauth2/token";
await auth.UsernamePasswordAsync(
consumerKey,
consumerSecret,
username,
password + securityToken,
tokenUrl);
forceClient = new ForceClient(auth.InstanceUrl, auth.AccessToken, auth.ApiVersion);
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"GetForceClient");
throw;
}
return forceClient;
}
}
Then I changed the method I am testing:
public async Task DeleteRecord<TSf>(TSf record)
where TSf : ISalesForceObject
{
try
{
var client = await this._forceClientService.GetForceClient();
var response = await client.DeleteAsync(typeof(TSf).Name, record.Id);
if (!response)
{
throw new Exception($"Error deleting record with ID {record.Id}");
}
}
catch (Exception e)
{
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, $"ForceDotComService.DeleteRecord");
throw;
}
}
Then I rebuilt my mock to mock the dependencies vs. the methods:
var mockForceClient = new Mock<IForceClient>();
mockForceClient
.Setup(
i => i.GetDeleted<DeletedRecordRootObject>(
It.IsAny<string>(),
It.IsAny<DateTime>(),
It.IsAny<DateTime>())).ReturnsAsync(deletedRecordRootObject);
var mockLogger = new Mock<ILogger<ForceDotComService>>();
var mockForceClientService = new Mock<IForceClientService>();
mockForceClientService.Setup(m => m.GetForceClient()).ReturnsAsync(mockForceClient.Object);
this._service = new ForceDotComService(mockLogger.Object, mockForceClientService.Object);
It is now working as expected. Thanks so much for the help!
Extract this.GetForceClient() out into its own service backed by an abstraction
public IForceClientProvider {
Task<IForceClient> GetForceClient();
}
you would then refactor your current class under test to explicitly depend on that interface via constructor injection.
public class ForceDotComService : IForceDotComService {
private readonly IForceClientProvider provider;
public ForceDotComService(IForceClientProvider provider) {
this.provider = provider;
}
public async Task<List<string>> GetDeletedRecordIds<T>(DateTime startDate)
where T : ISalesForceObject {
List<string> result;
try {
var client = await provider.GetForceClient();
var init = await client.GetDeleted<DeletedRecordRootObject>(typeof(T).Name, startDate, DateTime.Now);
result = init?.DeletedRecords.Select(d => d.Id).ToList();
} catch (Exception e) {
this._logger.LogError(LoggingEvents.GENERAL_ERROR, e, "GetDeletedRecordIds");
throw;
}
return result;
}
}
This would then allow you to mock the desired behavior when testing. In implementation code you would have the same code presented above in the GetForceClient() method.
You mock dependencies, not methods on the class under test.
You need to inject the dependency IForceClient, for example by making it a constructor parameter. Because now your GetForceClient() is simply being called on the class under test, which runs in that class and not on your mock, and so simply returns the new ForceClient() stated in there.
So I have created a provider which will handle all my code.
Originally it looked like this:
public class AnswerProvider : ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly AnswerService _answerService;
private QuestionService _questionService;
public QuestionService QuestionService => _questionService ?? (_questionService = new QuestionService(this._unitOfWork));
public AnswerProvider(IUnitOfWork unitOfWork)
{
this._unitOfWork = unitOfWork;
this._answerService = new AnswerService(unitOfWork);
}
public async Task<IHttpActionResult> CreateAsync(AnswerRequestModel model)
{
try
{
// Validate our answer count
await ValidateAnswerCountAsync(model.QuestionId);
// Create our model
var answer = ModelFactory.Create(model);
// Add our images to our answer
answer.Images = model.Images;
// Save our model
this._answerService.Create(answer);
// Save the database changes
await this._unitOfWork.SaveChangesAsync();
// Return our updated model
return Ok(ModelFactory.Create(answer));
// If there is an error
}
catch (Exception ex)
{
// Return our error
return BadRequest(ex.Message.ToString());
}
}
/// <summary>
/// Validates the answers based on the question type
/// </summary>
/// <param name="id">The id of the question</param>
/// <returns></returns>
private async Task ValidateAnswerCountAsync(int id)
{
// Get our question
var question = await this.QuestionService.GetAsync(id, "Answers");
// If we have 3 answers or more
if (question.Answers.Count >= 3 && question.Type == QuestionType.Boolean)
{
// Throw an error
throw new InvalidOperationException("A Boolean question can only have 3 answers");
}
}
}
I inherited ApiController because I want to gain access to the Ok, BadRequest and other such methods, that is the only reason.
When I try to run that code, even though it compiles I get this error:
HttpControllerContext.Configuration must not be null
I assume that is because I am trying to inherit the ApiController and I shouldn't be doing that.
Is there another way I can get access the the Ok and other similar methods without inheriting the ApiController.
Please bare in mind that I will have more than one provider.
Do not inherit from ApiController as this is instantiated by a factory in the request pipeline. You should only inherit it for actual api controller instances, not for convenience of some of the existing methods. The best solution would be to throw custom exceptions in your Provider/Service/ whatever and catch them in your controller and return the correct HttpStatus OR let the exception pass through and it would result in a 500 status.
As requested though I have created a small wrapper around the ApiController that you could reuse in your Provider/Service/etc based on an interface (so its easy to abstract this AND easy to test).
// demo of controller calling your Provider
public class SomeController : ApiController
{
public async Task<IHttpActionResult> Get()
{
var wrapper = this.ActionWrapper();
var answerProvider = new AnswerProvider(wrapper);
var result = await answerProvider.CreateAsync(model);
}
}
// a simple extension on the ApiController
public static class WrapperExtension
{
public static IActionWrapper ActionWrapper(this ApiController controller)
{
return new ApiActionWrapperContext(controller);
}
}
// wrapped in interface so its easy to unit test the Provider
public interface IActionWrapper
{
OkResult Ok();
BadRequestResult BadRequest();
BadRequestErrorMessageResult BadRequest(string message);
OkNegotiatedContentResult<T> Ok<T>(T content);
}
// the implementation, this takes the current Controller and uses it as the context to return the same result types
// only implemented Ok and BadRequest as a demo, you can extend it as needed
public class ApiActionWrapperContext : IActionWrapper
{
private ApiController _controller;
public ApiActionWrapperContext(ApiController controller)
{
_controller = controller;
}
public BadRequestResult BadRequest()
{
return new BadRequestResult(_controller);
}
public BadRequestErrorMessageResult BadRequest(string message)
{
return new BadRequestErrorMessageResult(message, _controller);
}
public OkResult Ok()
{
return new OkResult(_controller);
}
public OkNegotiatedContentResult<T> Ok<T>(T content)
{
return new OkNegotiatedContentResult<T>(content, _controller);
}
}
// provider shortered with just some relevant code to demo
// notice constructor, the new private field, and the use of it
public class AnswerProvider
{
private IActionWrapper _actionWrapper;
public AnswerProvider(IActionWrapper actionWrapper)
{
if(actionWrapper == null)
throw new ArgumentNullException("actionWrapper");
_actionWrapper = actionWrapper;
}
public async Task<IHttpActionResult> CreateAsync(AnswerRequestModel model)
{
try
{
// Validate our answer count
await ValidateAnswerCountAsync(model.QuestionId);
// Create our model
var answer = ModelFactory.Create(model);
// Add our images to our answer
answer.Images = model.Images;
// Save our model
this._answerService.Create(answer);
// Save the database changes
await this._unitOfWork.SaveChangesAsync();
// Return our updated model
return this._actionWrapper.Ok(ModelFactory.Create(answer));
// If there is an error
}
catch (Exception ex)
{
// Return our error
return this._actionWrapper.BadRequest(ex.Message.ToString());
}
}
}
I'm struggling to learn how to make tests, to test specifically and only business logic/rules in the Service layer only, using Moq tests.
Here's part of my project:
The Entity:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
}
The Repository:
public class ClientRepository : IClientRepository
{
private MyContext context;
public ClientRepository(MyContext context)
{
this.context = context;
}
public void Save(Client client)
{
try
{
context.Clients.Add(client);
context.SaveChanges();
}
catch (Exception)
{
throw new Exception("Error saving");
}
}
public void Delete(Client client)
{
Client cl = context.Clients.Where(x => x.Id == client.Id).FirstOrDefault();
if (cl != null)
{
context.Clients.Remove(client);
context.SaveChanges();
}
else
{
throw new Exception("Error deleting");
}
}
public List<Client> List()
{
return context.Clients.ToList();
}
public Client GetById(int Id)
{
return context.Clients.Where(x => x.Id == Id).FirstOrDefault();
}
}
The Repository Interface:
public interface IClientRepository
{
void Save(Client client);
void Delete(Client client);
List<Client> List();
Client GetById(int Id);
}
The Service:
public class ClientService
{
private ClientRepository rep;
public ClientService(MyContext ctx)
{
this.rep = new ClientRepository(ctx);
}
public void Save(Client client)
{
try
{
Validate(client);
rep.Save(client);
}
catch (Exception ex) {
Debug.WriteLine(ex.Message);
throw new Exception("Error Saving");
}
}
public void Delete(Client client)
{
try
{
if (client.Name.StartsWith("A"))
{
throw new Exception("Can't delete client with name
starting with A");
}
rep.Delete(client);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw new Exception("Error deleting");
}
}
public List<Client> List()
{
try
{
return rep.List();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
throw new Exception("Error list");
}
}
public void Validate(Client client)
{
if (client.Name.Length < 2)
{
throw new Exception("nome deve ser maior que 2");
}
}
public Client GetById(int Id)
{
return rep.GetById(Id);
}
}
My test:
[TestMethod]
public void CantSaveClientWithNameLengthLessThanTwo()
{
Client client = new Client() { Id = 4, Name = "a" };
var mockMyContext = new Mock<MyContext>();
mockMyContext.Setup(c => c.Clients.Add(client)).Throws<InvalidOperationException>();
var service = new ClientService(mockMyContext.Object);
service.Save(client);
int listCount = service.List().Count();
Assert.AreEqual(0, listCount);
}
In this test I want to test the business logic which prevents me from saving a client with a name that has less than 2 characters. Of course, this test is working incorrectly, and I end up getting an exception.
I'd like to know how to implement a test to test these 2 business requirements, and only that, in my project:
Can't save a client with less than 2 characters in the name.
Can't delete a client whose name starts with "A".
I'm using Microsoft Visual Studio 2010, Entity Framework 4.0 and Moq.
I appreciate any kind of help I can get, and suggestions of changes that I should make in the project, only if it isn't possible to accomplish what I want with my actual project pattern.
First of all, Inside the ClientService, you are creating an instance of your data access layer, ClientRepository by hard coding. This will make it hard to test it. So the better approach is to Inject the IRepository Implementation to the ClientService.
public class ClientService
{
private IClientRepository repo;
public ClientService(IClientRepository repo)
{
this.repo = repo;
// now use this.repo in your methods
}
}
Now for your tests, Your Validate method is throwing an exception when the Name property value has less than 2 chars. To test this, you can decorate your test method with ExpectedException attribute.
[TestMethod]
[ExpectedException(typeof(Exception))]
public void ValidateShouldThrowException()
{
var moqRepo = new Mock<IRepository>();
var cs = new ClientService(moqRepo.Object);
var client = new Client { Name = "S" };
cs.Save(client);
}
My recommendation is to not throw the general Exception, but use some specific exceptions like ArgumentException etc or your custom exception if you want.
For your second test where you want to pass a Name property value which has more than 2 chars, It should not throw the exception from the Validate. In this test, We will mock the Save behavior so that it won't actually try to save to the db ( which it should not)
[TestMethod]
public void SaveShouldWork()
{
var moqRepo = new Mock<IRepository>();
moqRepo.Setup(s=>s.Save(It.IsAny<Client>)).Verifiable();
var cs = new ClientService(moqRepo.Object);
var client = new Client { Name = "S" };
cs.Save(client);
//Test passed :)
}
My last suggestion is to extract out the validation code to a new class/interface combo and inject your Validator implementation to the ClientService. With this approach, you can inject another version of validation as needed.
public class ClientService
{
private IClientRepository repo;
private IValidator validator;
public ClientService(IClientRepository repo,IValidator validator)
{
this.repo = repo;
this.validator = validator
}
}
I have written a very simple WebApiClient extending HttpClient. The code is following. The main reason to do that was to throw MyOwnWebApiException when httpResponse.IsSuccessStatusCode is false.
public class WebApiClient : HttpClient
{
public WebApiClient(string apiBaseUrl)
{
this.BaseAddress = new Uri(apiBaseUrl);
this.DefaultRequestHeaders.Accept.Clear();
}
public void AddAcceptHeaders(MediaTypeWithQualityHeaderValue header)
{
this.DefaultRequestHeaders.Accept.Add(header);
}
public async Task<string> DoPost(string endPoint, Object dataToPost)
{
HttpResponseMessage httpResponse = await ((HttpClient)this).PostAsJsonAsync(endPoint, dataToPost);
if (httpResponse.IsSuccessStatusCode)
{
string rawResponse = await httpResponse.Content.ReadAsStringAsync();
return rawResponse;
}
else
{
string rawException = await httpResponse.Content.ReadAsStringAsync();
MyOwnWebApiErrorResponse exception =
JsonConvert.DeserializeObject<MyOwnApiErrorResponse>(rawException, GetJsonSerializerSettings());
throw new MyOwnWebApiException (exception.StatusCode,exception.Message,exception.DeveloperMessage,exception.HelpLink);
}
}
#region "Private Methods"
private static JsonSerializerSettings GetJsonSerializerSettings()
{
// Serializer Settings
var settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
ObjectCreationHandling = ObjectCreationHandling.Auto
};
return settings;
}
#endregion
Following is the code of the class using WebApiClient.
class TestWebApiClient
{
private WebApiClient _client;
public ComputationProcessesWebApiClient()
{
_client = new WebApiClient("http://test.api/");
_client.AddAcceptHeaders(new MediaTypeWithQualityHeaderValue("application/json"));
}
public void GetData(string dataFor)
{
try
{
DataRequest request = new DataRequest();
request.dataFor = dataFor;
**// THIS LINE IS THROWING AGGREGATEEXCEPTION--- **I WANT MyOwnException ****
string response = _client.DoPost("GetData", request).Result; // Use the End Point here ....
}
catch (MyOwnWebApiException exception)
{
//Handle exception here
}
}
}
Question
In the TestWebApiClient class, i dont want to catch AggregateException, rather i want to keep it more elegent and catch MyOwnWebApiException, but the problem is the line ** _client.DoPost("GetData", request).Result** throws an AggregateException if something goes wrong from the WebApi. How to change the code so that from TestWebApiClient i only have to catch MyOwnException ??
This is as a result of synchronously waiting for your task. If you stay async and await your task instead, you'll find that your actual Exception is the one that is caught.
Compare the following below:
void Main()
{
TryCatch();
TryCatchAsync();
}
void TryCatch()
{
try
{
ThrowAnError().Wait();
}
catch(Exception ex)
{
//AggregateException
Console.WriteLine(ex);
}
}
async Task TryCatchAsync()
{
try
{
await ThrowAnError();
}
catch(Exception ex)
{
//MyException
Console.WriteLine(ex);
}
}
async Task ThrowAnError()
{
await Task.Yield();
throw new MyException();
}
public class MyException:Exception{};
Top hint for async/await? It's async/await all the way down. The moment you .Wait() or .Result on a Task, things start to get messy.