I need to test and mock a method found inside a controller. Is is possible to mock a method inside the controller, without implementing an interface using NSubstitute framework.
Here is my Controller page code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Syncfusion.Cluster.Manager
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
int result = Sum(7, 7);
return View();
}
public virtual int Sum(int a, int b)
{
return 0;
}
}
}
Here is my Test code and the Sum always found to be '0' inside the controller while I debugged it. The Sum function inside the controller is not get overrides.
using System;
using NUnit.Framework;
using Manager;
using Base.Classes.Models.SecurityBase;
using NSubstitute;
using BaseProject;
using System.Web.Mvc;
using System.Web.Http;
namespace NSubstituteControllerSupport
{
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var controller = new HomeController();
//var actionMethod = Substitute.For<HomeController>();
//actionMethod.Sum(Arg.Any<int>(), Arg.Any<int>()).Returns(14);
//var actual = controller.Index();
var validation = Substitute.ForPartsOf<HomeController>();
validation.When(x => x.Sum(a: Arg.Is(7), b: Arg.Is(7))).DoNotCallBase();
validation.Sum(7, 7).Returns(14);
var actuals = controller.Index();
}
}
}
Here is my testing code for the Class Library project I successfully mocked a method without implementing an interface.
[Test]
public void TestMethod2()
{
#region variableDecleration
var adHost = new ActiveDirectoryHost();
adHost.AdPath = #"C:\User\Security\1.0.0.0";
adHost.CnNames = "CN=USERS";
adHost.DomainName = "USER.COM";
adHost.DomainPath = "DC=USER,DC=COM";
adHost.Fqn = "HOSTNAME.USER.COM.USER.COM";
adHost.HostName = "hostname.user.com";
adHost.OuPath = "OU=NewSecur";
adHost.SuperGroupName = "usergroup_1";
adHost.IpAddress = "xxx.xx.xx.x";
var adUserName = "username";
var adPassword = "password";
#endregion variableDecleration
var validation = Substitute.ForPartsOf<ValidationHandler>();
validation.GetUserGroupList(userName: Arg.Is(adUserName ), recursive: Arg.Is(false), adHost: Arg.Is(adHost), adUsername: Arg.Is(adUserName), adPassword: Arg.Is(adPassword)).Returns("usergroup_1,usergroup_2");
var isUserInGroup = validation.IsUserMemberOfGroup(adUsername, "usergroup_1", adHost, adUserName, adPassword);
Assert.That(isUserInGroup, Is.EqualTo(true));
}
The following should do the job:
// arrange
var controller = Substitute.For<HomeController>();
controller.Sum(7, 7).Returns(14);
// act
var actual = controller.Index();
// assert
...
Related
I am trying to retrieve records in my index ActionResult but keep getting a "The name 'connectionString' does not exist in the current context" error. Please see below code:
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestMVCApp.DAL;
using TestMVCApp.Models;
namespace TestMVCApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var objDAL = new DAL_InvoicesEntity();
List<InvoicesModel> invInfo = objDAL.RetriveRecords(connectionString);
ViewBag.invInfo = invInfo;
return View();
}
}
}
DAL class file:
using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using TestMVCApp.Models;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System.Linq;
namespace TestMVCApp.DAL
{
public class DAL_InvoicesEntity
{
public List<InvoicesModel> RetriveRecords(string connectionString)
{
var svc = new CrmServiceClient(connectionString);
var query = new QueryExpression()
{
EntityName = "new_invoices",
ColumnSet = new ColumnSet("new_invoicesid", "ttt_customer", "ttt_invoiceid", "ttt_paymentreceived", "ttt_commission", "ttt_adminfee", "ttt_discountamount"),
TopCount = 10
};
var invoices = svc.RetrieveMultiple(query).Entities.ToList();
var invoiceModels = invoices.Select(i =>
new InvoicesModel
{
InvoiceID = i.GetAttributeValue<Guid>("new_invoicesid"),
ClientName = i.GetAttributeValue<EntityReference>("ttt_customer"),
InvoiceNumber = i.GetAttributeValue<string>("ttt_invoiceid"),
AdminFee = i.GetAttributeValue<decimal>("ttt_adminfee"),
Discount = i.GetAttributeValue<decimal>("ttt_discountamount"),
PaymentReceived = i.GetAttributeValue<decimal>("ttt_paymentreceived")
})
.ToList();
return invoiceModels;
}
}
}
Please assist if you can
You should define connectionString variable before using it.
public class HomeController : Controller
{
private const connectionString = "YourConnectionString";
public ActionResult Index()
{
var objDAL = new DAL_InvoicesEntity();
List<InvoicesModel> invInfo = objDAL.RetriveRecords(connectionString);
ViewBag.invInfo = invInfo;
return View();
}
}
This is my repository method:
public async Task<IList<IVehicleMake>> GetAllMakes()
{
var makes = Context.VehicleMakes.AsQueryable();
return new List<IVehicleMake>(AutoMapper.Mapper.Map<List<VehicleMake>>(await makes.ToListAsync()));
}
I know how to mock the method that returns a concrete type, but as you can see, this method returns a list of Interfaces "IVehicleMake".
Is it possible to mock this kind of method and how?
You can simply use a mocking framework such as Moq. It is not so different than mocking a simple interface.
Here is a sample code using MS Test and Moq
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace UnitTestProject1
{
public class Vehicle{}
public interface IVehicleMake
{
Vehicle Make();
}
public interface IVehicleMakeRepository
{
Task<IList<IVehicleMake>> GetAllMakes();
}
public class MyService
{
private readonly IVehicleMakeRepository vehicleMakeRepository;
public MyService(IVehicleMakeRepository vehicleMakeRepository)
{
this.vehicleMakeRepository = vehicleMakeRepository;
}
public async Task DoSomething()
{
var makes = await vehicleMakeRepository.GetAllMakes();
foreach (var make in makes)
{
var vehicule = make.Make();
}
}
}
public class MyServiceTest
{
[TestClass]
public class DoSomething
{
[TestMethod]
public async Task Should_CallAllMakersOnce()
{
//Arrange
var mockedMakers = new[] { new Mock<IVehicleMake>(), new Mock<IVehicleMake>(), };
foreach (var mockedMaker in mockedMakers)
{
mockedMaker.Setup(m => m.Make()).Returns(new Vehicle()).Verifiable();
}
var mockedRepository = new Mock<IVehicleMakeRepository>();
mockedRepository
.Setup(m => m.GetAllMakes())
.ReturnsAsync(mockedMakers.Select(mm => mm.Object).ToList())
.Verifiable();
var service = new MyService(mockedRepository.Object);
//Act
await service.DoSomething();
//Assert
mockedRepository.Verify(m => m.GetAllMakes(), Times.Once);
foreach (var mockedMaker in mockedMakers)
{
mockedMaker.Verify(m => m.Make(), Times.Once);
}
}
}
}
}
I'm fairly new to .NET and c# and I'm working on a POC where I've run into an issue when a controller throws the error
System.InvalidOperation Exception {"Unable to resolve controller: TenantController"}
The Inner exception details are
No default Instance is registered and cannot be automatically determined for type 'GICS.Web.Managers.Interfaces.ITenantManager'
There is no configuration specified for GICS.Web.Managers.Interfaces.ITenantManager
1.) new TenantController(Default of ITenantManager, Default of IRemedyService)
2.) GICS.Web.Controllers.Api.TenantController
3.) Instance of GICS.Web.Controllers.Api.TenantController
4.) Container.GetInstance(GICS.Web.Controllers.Api.TenantController)
The TenantController looks as follows:
using System.Web.Mvc;
using GICS.Web.Controllers.Api.Abstracts;
using GICS.Web.Managers.Interfaces;
using GICS.Web.Services.Interfaces;
using System.Collections.Generic;
using GICS.Web.ViewModels.Tenant;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Controllers.Api
{
[RoutePrefix("api/tenant")]
public class TenantController : BaseApiController
{
private readonly ITenantManager _tenantsManager;
private readonly IRemedyService _remedyService;
private string token;
public TenantController(ITenantManager tenantsManager, IRemedyService remedyService)
{
_tenantsManager = tenantsManager;
_remedyService = remedyService;
token = null;
}
[HttpGet, Route("{groupId}/{userName}")]
public JsonResult getTenants(string groupId, string UserName)
{
getToken(UserName);
JsonResult result = Json(null);
if (token != null)
{
var tenants = _tenantsManager.GetTenants(token, groupId);
List<TenantViewModel> tenantViewModelList = new List<TenantViewModel>();
foreach (Values x in tenants)
{
TenantViewModel model = new TenantViewModel(x, groupId);
tenantViewModelList.Add(model);
}
result = Json(tenantViewModelList);
}
return result;
}
}
The TenantManager interface is as follows:
using System.Collections.Generic;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers.Interfaces
{
public interface ITenantManager
{
IEnumerable<Values> GetTenants(string token, string groupId);
}
}
And the Manager implementation is:
using GICS.Web.Managers.Abstracts;
using GICS.Web.Managers.Interfaces;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers
{
public class TentantManager : ManagerBase, ITenantManager
{
public IEnumerable<Models.Tenant.Values> GetTenants(string token, string groupId)
{
Tenant restEntries = null;
List<Models.Tenant.Values> tenantList = new List<Models.Tenant.Values>();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.Authorization] = token;
var baseURL = ConfigurationManager.AppSettings["RemedyBaseUrl"];
var apiPath = ConfigurationManager.AppSettings["RemedyAPIPath"];
string getURL = baseURL + apiPath + "ESN%3AAST%3ALogSysComp%5FASTPeople" + "?q=?q=%27PeopleGroup%20Form%20Entry%20ID%27%20%3D%20%22" + groupId + "%22&fields=values(Name)";
string getResponse = client.DownloadString(getURL);
restEntries = JsonConvert.DeserializeObject<Tenant>(getResponse);
foreach (Models.Tenant.Entry x in restEntries.entries)
{
tenantList.Add(x.values);
}
}
return tenantList;
}
}
}
I have other controllers in the project that follow the same approach and all are working except for this one. Anyone spot where I am going wrong here?
Thanks in advance.
I want to test if my code works properly so I am writing some unit tests for it.
I want to check when and item in my list with the same values is added again it should return false.
I do not really understand how to set this up. I hope some can help me out.
Below my code
GuestResponseRepository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PartyInvites.Abstract;
namespace PartyInvites.Models
{
public class GuestResponseRepository : IRepository
{
private static List<GuestResponse> responses = new List<GuestResponse>();
IEnumerable<GuestResponse> IRepository.GetAllResponses()
{
return responses;
}
bool IRepository.AddResponse(GuestResponse response)
{
if (responses.Any(x => x.Email == response.Email)) //here
{
if (responses.Any(x => x.WillAttend == response.WillAttend)) //here
{
return false;
}
var attend = responses.First(x => x.Email == response.Email && x.WillAttend != response.WillAttend);
attend.WillAttend = response.WillAttend;
return true;
}
responses.Add(response);
return true;
}
}
}
My interface which communicates with the GuestResponseRepository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PartyInvites.Models;
namespace PartyInvites.Abstract
{
public interface IRepository
{
IEnumerable<GuestResponse> GetAllResponses();
bool AddResponse(GuestResponse response);
}
}
A piece of my Homecontroller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PartyInvites.Models;
using PartyInvites.Abstract;
namespace PartyInvites.Controllers {
public class HomeController : Controller {
private IRepository repository;
public HomeController(IRepository iRepository)
{
this.repository = iRepository;
}
[HttpGet]
public ViewResult RsvpForm() {
return View();
}
[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse) {
if (ModelState.IsValid) {
bool result = repository.AddResponse(guestResponse);
ViewBag.Response = result;
repository.AddResponse(guestResponse);
return View("Thanks", guestResponse);
}
else
{
// there is a validation error
return View();
}
}
}
}
My UnitTest what I got so far
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PartyInvites.Abstract;
using PartyInvites.Controllers;
using PartyInvites.Models;
using Moq;
namespace Aanmelden
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void FirstResponse()
{
//Arange
Mock<IRepository> mock = new Mock<IRepository>();
mock.Setup(m => m.AddResponse()).Returns(new GuestResponse[] {
new GuestResponse {Name = "Valheru", Email = "valheru#hotmail.com", Phone = "12345678", WillAttend = true}
});
HomeController controller = new HomeController(mock.Object);
//Act
new GuestResponse
{
Name = "Valheru",
Email = "valheru#hotmail.com",
Phone = "12345678",
WillAttend = true
};
//Assert
if viewbag.response = result == false test succeeded
}
}
}
for some reason mock.Setup(m => m.**AddResponse**()).Returns(new GuestResponse[] {...
"AddResponse" aint right says Visual Studio ->
there is no argument given that corresponds to the required formal
parameter 'response' of IRepository.AddResponse(GuestReponse)
I am also no sure about my Act piece of code and I lost it totally with the Assert part. I hope someone can help me out!
you should It.IsAny<GuestResponse>() as a paramater in order to match the signature of your interface
Mock<IRepository> mock = new Mock<IRepository>();
mock.Setup(m => m.AddResponse(It.IsAny<GuestResponse>())).Returns(true);
Based on
I want to check when an item in my list with the same values is added
again it should return false.
You should actually be testing the GuestResponseRepository implementation itself and not the controller.
[TestMethod]
public void Duplicate_Added_Should_Return_False {
//Arrange
var sut = new GuestResponseRepository();
var model = new GuestResponse
{
Name = "Valheru",
Email = "valheru#hotmail.com",
Phone = "12345678",
WillAttend = true
};
sut.AddResponse(model);
var expected = false;
//Act
var actual = sut.AddResponse(model);
//Assert
Assert.AreEqual(expected, actual);
}
Update: HttpTest is not thread-safe, as per the project's GitHub issue. Until the issue is resolved, tests using HttpTest cannot be run in parallel.
I have a really weird pair of test utilizing Flurl and xUnit that, when Run All in VS Test Explorer, will fail, but if run individually, will pass. I cannot for the life of me see anywhere where the 2 are even related to each other, but they do.
I have extracted them out of my project into a new project and the problem persists. I bundled them into a 7z for anyone interested in loading it to VS, but the full code follows.
Project.Commons
GetApi1:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi1
{
public async Task<string> ExecuteAsync(string token)
{
string apikeyKeyname = "token";
dynamic response = await "http://www.api.com"
.SetQueryParams(new { token = token })
.GetJsonAsync();
string receivedApiKey = ((IDictionary<string, object>)response)[apikeyKeyname].ToString();
return receivedApiKey;
}
}
}
GetApi2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi2
{
public async Task<IList<string>> ExecuteAsync()
{
var responses = await "http://www.api.com"
.GetJsonAsync<List<string>>();
var result = new List<string>();
foreach (var response in responses)
{
result.Add("refined stuff");
}
return result;
}
}
}
Project.Tests
UnitTest1:
using Project.Commons;
namespace Project.Tests
{
public class UnitTest1
{
private ITestOutputHelper output;
public UnitTest1(ITestOutputHelper output)
{
this.output = output;
}
[Fact]
public async Task ShouldBeAbleToGetApiKeyFromToken()
{
// Arrange
using (var httpTest = new HttpTest())
{
var jsonResponse = new { token = "abcdef" };
string expectedApiKey = "abcdef";
httpTest.RespondWithJson(jsonResponse);
var api = new GetApi1();
// Act
var receivedApiKey = await api.ExecuteAsync("mockToken");
output.WriteLine("Received apikey = " + receivedApiKey);
// Assert
Assert.Equal(expectedApiKey, receivedApiKey);
}
}
}
}
UnitTest2
using Flurl.Http.Testing;
using Project.Commons;
using Xunit;
using Xunit.Abstractions;
namespace Project.Tests
{
public class UnitTest2
{
#region Mock API JSON Response
private IList<string> mockResponse = new List<string>()
{
"raw stuff", "raw stuff", "raw stuff"
};
#endregion
#region Expected Result
private IList<string> expectedResult = new List<string>()
{
"refined stuff", "refined stuff", "refined stuff"
};
#endregion
[Fact]
public async Task CanGetProjectsByWeek()
{
// Arrange
using (var httpTest = new HttpTest())
{
httpTest.RespondWithJson(mockResponse);
// Act
var api = new GetApi2();
var actualResult = await api.ExecuteAsync();
// Assert
Assert.Equal(expectedResult,actualResult);
}
}
}
}
The comments are correct - lack of thread safety is a known limitation of HttpTest. It is logged and under investigation. Parallel testing is much more prevalent today than just a couple years ago when this was created, so while a fix is not trivial, we are treating it with high priority.