I have a dotnetcore web app and am looking to unit test the controllers. How do I get about this?
I have a simple controller that looks like this
public class ConversionController : Controller {
private readonly INumberService _numberService;
public ConversionController(INumberService numberService)
{
this._numberService = numberService;
}
// GET http://localhost:9789/api/conversion/123
[HttpGet("{number}")]
public string Get(decimal number)
{
return _numberService.ConvertToWords(number);
}
}
The INumberService is passed in as a parameter. How do I unit test this?
By mocking the interface/dependency and exercising an isolated unit test for the Get method. You could either create your own mock or use a mocking framework to mock the dependency. From there assert that the system under test behaves as expected.
For example the following simple test uses Moq to mock the dependency and test the Get method.
[TestMethod]
public void ConversionController_Get_Should_Return_Five() {
//Arrange
var number = 5;
var expected = "five";
var mock = new Mock<INumberService>();
mock.Setup(_ => _.ConvertToWords(number)).Returns(expected);
var sut = new ConversionController(mock.Object);
//Act
var actual = sut.Get(number);
//Assert
Assert.AreEqual(expected, actual);
}
You should also take some time and check the documentation provided
Unit Testing in .NET Core
Related
I have a project that supports multiple deployments mode: InMem, OnPremise, Cloud.
Also each projects have small services like TimeDistance which can be conected either to WCF, either to an API.
In the unitTestMockup i can say which one i want to use:
Service.TimeDistance = new WCFTimeDistance() / new APITimeDistance().
Until now i had only WCFTimeDistance but now we are in transition mode to move to APITimeDistance but in the meantime i want when i run the tests to run twice, once with WCF once with API.
What's a good approach to do this?
I use C# 4.5
Microsoft.VisualStudio.QualityTools.UnitTestFramework as framework for unitTests
A simple example of desired workflow would be this:
1)Mockup: Service.TimeDistance = new WCFTimeDistance();
2)UnitTest: CheckDistanceBetweenTwoLocationsTest()
{
Service.TimeDistance.CalculateDistance(Location1, Location2) // WCFTimeDistance
}
3)Mockup: Service.TimeDistance = new APITimeDistance();
UnitTest: CheckDistanceBetweenTwoLocationsTest()
{
4)Service.TimeDistance.CalculateDistance(Location1, Location2) // APITimeDistance
}
Create two unit tests. Also look into using abstractions instead of static classes. It would make mocking and testing easier.
This is for your current setup
[TestClass]
public class TimeDistanceTests {
//change these to the needed types
object Location1;
object Location2;
double expected;
[TestInitialize]
public void Init() {
//...setup the two locations and expectations
Location1 = //...
Location2 = //...
expected = //...the distance.
}
[TestMethod]
public void Check_Distance_Between_Two_Locations_Using_WCF() {
//Arrange
var sut = new WCFTimeDistance();
//Act
var actual = sut.CalculateDistance(Location1, Location2);
//Assert
//...some assertion proving that test passes or failed
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void Check_Distance_Between_Two_Locations_Using_API() {
//Arrange
var sut = new APITimeDistance();
//Act
var actual = sut.CalculateDistance(Location1, Location2);
//Assert
//...some assertion proving that test passes or failed
Assert.AreEqual(expected, actual);
}
}
Ideally you would want to abstract the service. Assuming something like
public interface ITimeDistance {
double CalculateDistance(Location location1, Location location2);
}
Your Service would use the abstraction instead of a concretion.
public class Service {
ITimeDistance timeDistance
public Service(ITimeDistance timeDistance) {
this.timeDistance = timeDistance;
}
public ITimeDistance TimeDistance { get { return timeDistance; } }
}
So now in your unit tests you can swap the different implementations of your time distance service.
Please help me with my issue. I have a Service class which is given below:
public class RateService:IRatesService
{
...
public RatesDTO GetById(int Id)
{
return Mapper.Map<Rates, RatesDTO>(this.db.Rates.GetAll().Where(m => m.RateId == Id).First());
}
}
An interface IRatesServicelooks like that sample of code:
public interface IRatesService
{
.....
RatesDTO GetById(int Id);
....
}
And now I try to test public RatesDTO GetById(int Id) method. My code is given below:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Mock<IRatesService> mock = new Mock<IRatesService>();
mock.Setup(m => m.GetById(It.IsAny<int>())).Returns<RatesDTO>(total=>total);
Assert.IsNotNull(mock.Object.GetById(1));
}
}
But when I run test I get an error like this:
Test Name: TestMethod1 Test
FullName: Provider.Tests.Services.UnitTest1.TestMethod1
Result Message:
Test method Provider.Tests.Services.UnitTest1.TestMethod1 threw
exception: System.ArgumentException: Невозможно преобразовать объект
типа "System.Int32" к типу "Provider.BLL.DTO.RatesDTO".
What is the best practice to test the Service classes and methods?
You are trying to test your mock. That doesn't make any sense.
You should strive to test your actual code.
In your case, you might want to make sure that your GetById returns RatesDTO with the right id value.
You could use Mock framework, to facilitate your testing.
e.g. if you are trying to perform a unit-test and you are using a DB layer you might want to mock the database layer GetAll function and return several objects and then run a test to check that you actually return the right object (same id).
Your RateService is the system under test. When creating mocks for your unit tests the norm is to mock the dependencies of your system under test.
So given your current service lets say it has a dependency on a data store.
public class RateService : IRatesService {
private readonly IDbContext db;
public RateService(IDbContext dbContext) {
this.db = dbContext;
}
//...
public RatesDTO GetById(int Id) {
return Mapper.Map<Rates, RatesDTO>(this.db.Rates.GetAll().Where(m => m.RateId == Id).First());
}
//...
}
IDbContext would be the dependency of the system under test.
You would mock that up when testing RateService
[TestClass]
public class RateServiceUnitTests {
[TestMethod]
public void Given_ValidId_GetById_Should_Return_Dto() {
//Arrange
var validId = 1;
var fakes = new List<Rates>() {
new Rates { RateId = validId }
};
var mock = new Mock<IDbContext>();
//Assuming IDbContext.Rates.GetAll() returns an IEnumerable<Rates>
mock.Setup(m => m.Rates.GetAll()).Returns(fakes);
var sut = new RateService(mock.Object);
//Act
var result = sut.GetById(validId);
//Assert
Assert.IsNotNull(result);
}
}
Noticed that you are also using a mapper. You should make sure that is configured for the test as well otherwise the test will fail. When using static calls in your classes they can cause issues when you try to isolate your system for testing. Try adding the mapper as a dependency as well.
I'm practicing on writing unit tests for the first time, and I have some questions. I'll start of by explaining what I'm trying to test.
I would like to test a method which looks like this:
public bool IsAdmin(HubCallerContext hubCallerContext)
{
return hubCallerContext.User.IsInRole("admin");
}
The method is implemented in a class UserService, which is connected to a interface IUserService.
I'm trying to create 2 tests:
One with a HubCallerContext which is in the role of "admin" and will assert true.
One with a HubCallerContext which is in the role of "user" and will assert false.
I've created a new class library in my solution, where I've refrenced the project I'm testing. I've installed NUnit and Moq, and created a test class which looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChatProj;
using NUnit.Framework;
using ChatProj.Controllers;
using Moq;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using ChatProj.DAL;
using ChatProj.Service_Layer;
using System.Threading.Tasks;
namespace ChatProj.Tests
{
[TestFixture]
public class Class1
{
[SetUp]
public void Setup()
{
}
[Test]
public void IsAdmin_CalledByAdmin_ReturnTrue()
{
UserService userService = new UserService();
bool result = userService.IsAdmin( ? );
Assert.IsTrue( result, "Something is wrong." );
}
[Test]
public void IsAdmin_CalledByUser_ReturnFalse()
{
UserService userService = new UserService();
bool result = userService.IsAdmin( ? );
Assert.IsFalse( result, "Something is wrong." );
}
}
}
Here I start to get confused. (I've marked the parameters of the IsAdmin calls with "?" because I'm not sure what to put there.)
I've read about mocks, stubs, fakes and dummies, but the definitions are to abstract for me to really grasp. I've found these definitions for example:
- Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
- Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
- Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
- Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
As I've designed my test class, I would need some sort of substitution for my HubCallerContext. This is assuming I'm testing the "IsAdmin" method the right way.
So my questions are:
Am I testing the "IsAdmin" method in a good way?
How would I practically make the tests work? Do I use a mock, and in that case, could you show how I would implement that, or point me in the right direction? Here is how the HubCallerContext works for
refrence.
Assuming HubCallerContext is this one - https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Core/Hubs/HubCallerContext.cs - then setting up the tests will be easy. You just want two mocks of IPrincipal, one of which returns true for the .IsInRole("admin") call and the other that returns false.wrap these two in mocks of IRequest.
The syntax will vary depending on the mocking framework used, but your tests will end up something like:
[Test]
public void IsAdmin_CalledByAdmin_ReturnTrue()
{
UserService userService = new UserService();
var principalMock = new Mock<IPrincipal>();
principalMock.Setup(x => x.IsInRole("admin")).Returns(true);
var requestMock = new Mock<IRequest>();
requestMock.Setup(x => x.User).Returns(principalMock.Object);
var result = userService.IsAdmin(new HubCallerContext(requestMock.Object, ""));
Assert.IsTrue( result, "Something is wrong." );
}
[Test]
public void IsAdmin_CalledByUser_ReturnFalse()
{
UserService userService = new UserService();
var principalMock = new Mock<IPrincipal>();
principalMock.Setup(x => x.IsInRole("admin")).Returns(false);
var requestMock = new Mock<IRequest>();
requestMock.Setup(x => x.User).Returns(principalMock.Object);
var result = userService.IsAdmin(new HubCallerContext(requestMock.Object, ""));
Assert.IsFalse( result, "Something is wrong." );
}
I haven't checked if the above compiles, but it is based on the syntax needed for Moq.
I think that it would be much easier for You to write these two unit tests if You would change the method under test a little (assuming it's not a part of legacy code).
If you define the method this way:
public bool IsAdmin(IPrincipal user)
{
return user.IsInRole("admin");
}
things would get pretty simple (btw. check the "Law of Demeter" ;)). You can pass in a mock object (since the user parameter is an interface - IPrincipal) returning true if the user should be in role "admin" and false otherwise.
The benefit of this solution is that You don't have to build a graph of mock objects and the arrange part of your test is pretty simple. Your tests could look somewhat like this:
[Test]
public void IsAdmin_CalledByAdminUser_ReturnTrue()
{
//Arrange
var principalMock = new Mock<IPrincipal>();
principalMock.Setup(x => x.IsInRole("admin")).Returns(true);
//Act
var userService = ...// create an instance of userService here
var result = userService.IsAdmin(principalMock);
//Assert
Assert.IsTrue(result);
}
[Test]
public void IsAdmin_CalledByNonAdminUser_ReturnFalse()
{
//Arrange
var principalMock = new Mock<IPrincipal>();
principalMock.Setup(x => x.IsInRole("admin")).Returns(false);
//Act
var userService = ...// create an instance of userService here
var result = userService.IsAdmin(principalMock);
//Assert
Assert.IsFalse(result);
}
I would recommend You to read this series of blog posts (I think it's pretty cool :)): http://www.daedtech.com/tag/unit-testing
You can get the list of roles and check for each roles using foreach.
How do I creat a pure stub using Moq? With Rhino Mocks I did it like this:
[TestFixture]
public class UrlHelperAssetExtensionsTests
{
private HttpContextBase httpContextBaseStub;
private RequestContext requestContext;
private UrlHelper urlHelper;
private string stylesheetPath = "/Assets/Stylesheets/{0}";
[SetUp]
public void SetUp()
{
httpContextBaseStub = MockRepository.GenerateStub<HttpContextBase>();
requestContext = new RequestContext(httpContextBaseStub, new RouteData());
urlHelper = new UrlHelper(requestContext);
}
[Test]
public void PbeStylesheet_should_return_correct_path_of_stylesheet()
{
// Arrange
string expected = stylesheetPath.FormatWith("stylesheet.css");
// Act
string actual = urlHelper.PbeStylesheet();
// Assert
Assert.AreEqual(expected, actual);
}
}
How would I create a stub for MockRepository.GenerateStub<HttpContextBase>(); using Moq? Or should I just stay with Rhino Mocks?
Here is my suggestion for you:
Mock<HttpContextBase> mock = new Mock<HttpContextBase>();
mock.SetupAllProperties();
Then you have to do the setup.
For further informations see homepage of the MOQ project.
A bit late to the party here but there's still not a sufficient answer here in my opinion.
Moq doesn't have explicit stub and mock generation in the same way RhinoMocks does. Instead, all setup calls, e.g. mockObject.Setup(x => blah ...) create a stub.
However, if you want the same code be treated as a mock, you need to call mockObject.Verify(x => blah ...) to assert that the setup ran as you expected.
If you call mockObject.VerifyAll(), it will treat everything you have setup as mocks and this is unlikely to be the behaviour you wish, i.e. all stubs treated as mocks.
Instead, when setting up the mock use the mockObject.Setup(x => blah ...).Verifiable() method to mark the setup explicitly as a mock. Then call mockObject.Verify() - this then only asserts the setups that have been marked with Verifiable().
var mockHttpContext = new Mock<HttpContextBase>();
I've been using Moq for the past week or so and haven't had any issues until today. I'm having a problem with getting VerifyAll() to properly match the setup of my mock.
I'm currently writing unit tests for my application's API. Here's how the application is structured:
API <==> Service <==> DAO <==> Database
With this in mind, I'm mocking the service object and then constructing an API object using the mocked service. I've written a number of unit tests already without problem up until now.
I have two instance variables like this:
private Api _api;
private Mock<IHibernateService> mockService;
I initialize these in a setup method:
[SetUp]
public void DoSetupTasks()
{
mockService = new Mock<IHibernateService>();
_api = new Api(mockService.Object);
}
Here is the unit test that is failing:
[Test]
public void TestSearchOnAllProperties()
{
mockService
.Setup(service => service.LoadAll(It.IsAny<Type>()))
.Returns(new DomainBase[0]);
var dmbs = _api.SearchOnAllProperties("search term", typeof(DomainBase));
mockService.VerifyAll();
}
The API's SearchOnAllProperties() method will subsequently make a call to the service's LoadAll() method (with some additional logic of course), so I want to verify that it's being called properly. To clarify, here's how LoadAll() is being called in SearchOnAllProperties():
public IEnumerable<DomainBase> SearchOnAllProperties(string searchTerm, Type type)
{
foreach (DomainBase dmb in _hibernateService.LoadAll(type))
{
// additional logic
}
}
However, when I run the unit test, I get a MockVerificationException stating that the given setup was not matched. I cannot figure out why as it should be calling the service's LoadAll() method.
One possible cause is that at some point before this particular test method is called, mockService is being assigned to a new instance of Mock<IHibernateService>. If that is the case, then this test method would be calling Setup on the wrong instance, which would then produce this exception.
A quick way to test this would be to use local mockService and api variables and see if the test still fails:
[Test]
public void TestSearchOnAllProperties()
{
var localMockService = new Mock<IHibernateService>();
var localApi = new Api(localMockService.Object);
localMockService
.Setup(service => service.LoadAll(It.IsAny<Type>()))
.Returns(new DomainBase[0]);
var dmbs = localApi.SearchOnAllProperties("search term", typeof(DomainBase));
localMockService.VerifyAll();
}
HTH