Im trying with this TestMethod
[TestMethod]
[Description("Checks if the SearchResults Controller is generating any data from the Report")]
public async Task GetAllOldCustomersContainingTerm_FromSearchResultsControllerTest()
{
// Create mock configuration files for every class
DalConfig config = new DalConfig()
{
ConnectionString = "Trusted_Connection=True;database=AdventureWorks2017;Server=localhost\\MSSQL2017",
};
// Create mock options, PrintService and logger
var mockOptions = new Mock<IOptions<DalConfig>>();
mockOptions.Setup(op => op.Value).Returns(config);
var searchResultFunctions = new SearchResultFunctions();
var logger = new Logger<SearchResultsController>(new LoggerFactory());
var mockSearchResultServices = new Mock<SearchResultService>().As<ISearchResultService>();
mockSearchResultServices.CallBase = true;
// Terms to test. In MockDatabase, John exist on FirstName and 12345 on PostalCode
var terms = new SearchTerms
{
FirstName = "John",
PostalCode = "123456"
};
mockSearchResultServices.Setup(x => x.GetAllOldCustomersContainingTermAsync(config, terms))
.ReturnsAsync(new WebApiMockDatabaseRecordsProvider().GetAllMockOldCustomersDtos());
// Create mock controller
var testController = new SearchResultsController(logger, mockSearchResultServices.Object, searchResultFunctions, mockOptions.Object);
var result = await testController.GetAllOldCustomersContainingTermAsync() as OkObjectResult;
// Check if data is being returned from the Controller
Assert.IsTrue(result.Value != null);
To test the following controller.
Before i use QueryString i had a HttpGet with parameters and the test was succesful:
[ApiController]
[Route("[controller]")]
public class SearchResultsController : ControllerBase
{
readonly ILogger<SearchResultsController> _logger;
ISearchResultService ResultService;
ISearchResultFunctions ResultFunctions;
DalConfig DalConfig;
public SearchResultsController(ILogger<SearchResultsController> logger
, ISearchResultService resultService, ISearchResultFunctions resultFunctions, IOptions<DalConfig> settings)
{
DalConfig = settings.Value;
ResultService = resultService;
ResultFunctions = resultFunctions;
_logger = logger;
}
/// <summary>
/// Returns all customers with values that matches in any of the terms
/// Searches all the customer fields except BusinessEntityId and BirthDate
/// </summary>
/// <param name="terms">a list of string terms, seperated by space</param>
/// <returns></returns>
[HttpGet("FindOldCustomers/{terms?}")]
public async Task<IActionResult> GetAllOldCustomersContainingTermAsync()
{
//if (terms == null)
var terms = new SearchTerms()
{
FirstName = Request.Query["FirstName"],
LastName = Request.Query["LastName"],
EmailAddress = Request.Query["EmailAddress"],
Gender = Request.Query["Gender"],
AddressLine1 = Request.Query["AddressLine1"],
AddressLine2 = Request.Query["AddressLine2"],
City = Request.Query["City"],
JobTitle = Request.Query["JobTitle"],
PhoneNumber = Request.Query["PhoneNumber"],
PostalCode = Request.Query["PostalCode"],
};
var config = new DalConfig()
{
ConnectionString = DalConfig.ConnectionString,
};
var task = await ResultService.GetAllOldCustomersContainingTermAsync(config, terms);
if (task.Count == 0)
return NotFound();
return Ok(ResultFunctions.ConvertToJSON(task));
}
Im getting null reference exception, im not sure why.
Also im not sure if i somehow must pass to the controler the terms object. With parameters i was passing the terms from parameters.
I don't think the null check (as suggested in your answer) is the right approach here. While I wouldn't normally argue against that, there would be no way that the Request object could be null in a production environment. In fact, by adding the null check, you are allowing the test to branch such that it is not really testing the functionality of the method as used in production.
The real solution would be to mock the Request so that you can provide the query string parameters that are expected by the Controller method. See this answer for some advice on that.
I Added in the controller a check to see if Request is null and now test passes
Related
I have class city:
public class City
{
public int Id { get; set; }
[Required(ErrorMessage = "This field is required (server validation)")]
public string Name { get; set; }
[Range(1, 100000000, ErrorMessage = "ZIP must be greater than 1 and less than 100000000 (server validation)")]
public int ZIP { get; set; }
[Range(1, 2000000000, ErrorMessage = "Population must be between 1 and 2B (server validation)")]
public int Citizens { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
}
I have in controller post action for add city:
[HttpPost]
public IActionResult PostCity(City city)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_cityRepository.Add(city);
return CreatedAtAction("GetCity", new { id = city.Id }, city);
}
and I have test for invalid model:
[Fact]
public void PostCity_InvalidModel_ReturnsBadRequest()
{
// Arrange
City city = new City() { Id=15, Name = "", ZIP = 0, CountryId = 1, Citizens = 0 };
var mockRepository = new Mock<ICityRepositroy>();
var mapperConfiguration = new MapperConfiguration(cfg => cfg.AddProfile(new CityProfile()));
IMapper mapper = new Mapper(mapperConfiguration);
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
// Assert
Assert.NotNull(actionResult);
}
I debug test and I always get modelState.IsValid = true. When I try in postman to send invalid request, server validation works fine. Why my validation doesn't work in my test? ASP .Net Core framework is 5.0.
Your test call the method controller.PostCity(city) directly, while in the web server, when calling the endpoint, a whole bunch of middle ware is triggered and executed first.
One of this being the modelbinder, which I believe also performs the model validation.
So this will not work, because calling the ModelState.IsValid without any further initialization, causes it to return true as by default:
var controller = new CitysController(mockRepository.Object, mapper);
// Act
var actionResult = controller.PostCity(city) as BadRequestResult;
In stead you either need to connect the proper validation mechanism of the model, or even better (IMO) use the test web server which can do this in an easy controllable way.
Here's basically how to do it, but I recommend you to read some of the following articles as well (source: MSDN):
public class PrimeWebDefaultRequestShould
{
private readonly TestServer _server;
private readonly HttpClient _client;
public PrimeWebDefaultRequestShould()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>());
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnHelloWorld()
{
// Act
var response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal("Hello World!", responseString);
}
}
In the code above you'll need to replace the likes like EnsureSuccessStatusCode with you actual BadRequest test case.
Some additional reads:
https://www.meziantou.net/testing-an-asp-net-core-application-using-testserver.htm
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/test-aspnet-core-services-web-apps
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
https://www.roundthecode.com/dotnet/asp-net-core-web-api/asp-net-core-testserver-xunit-test-web-api-endpoints
More info on the pipelines, by MSDN:
It's because when you start the WebApi, and send a real request to it, behind the scenes it calls several methods in which it's validating your request, before it calls your controller action. In those methods it's setting the ModelState.IsValid property to false. On the other hand when you call your controller action directly from tests, nothing validates your request, hence your ModelState.IsValid is set to true by default.
New to Unit Testing web api.
I am writing a Unit test to Test a controller and I have to mock Iconfiguration. The appsettings,json has a section called "AppSettings", I'm trying to mock it.
Also, the mock.setup returns null value in the controller causing it to fail.
Here is my controller:
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
private readonly ICarPairingTable PairingTable;
private readonly ICarDealerSettingsTable DealerSettingsTable;
static AppSettings appSettings = null;
public CarController(IConfiguration configuration, ICarPairingTable carPairingTable, ICarDealerSettingsTable settingsTable)
{
_configuration = configuration;
appSettings = configuration.Get<AppSettingsModel>().AppSettings;
PairingTable = carPairingTable;
DealerSettingsTable = settingsTable;
}
[HttpGet]
public ActionResult Get(string id){
string DealerId ="";
DealerId = PairingTable.GetDealerId(id).Result;
if (string.IsNullOrEmpty(DealerId))
{
result = new ReturnResult
{
status = "Fail",
data = "ID is invalid"
};
return NotFound(result);
}
SettingsInfo info = DealerSettingsTable.GetSettingsInfo(DealerId).Result;
if (info == null)
{
result = new ReturnResult
{
status = "Fail",
data = "Not Found"
};
return NotFound(result);
}
result = new ReturnResult
{
status = "Success",
data = info
};
return Ok(result);
}
Here is my Unit Test:
[Fact]
public void Test1()
{
var mockConfig = new Mock<IConfiguration>();
var configurationSection = new Mock<IConfigurationSection>();
configurationSection.Setup(a => a.Value).Returns("testvalue");
mockConfig.Setup(a => a.GetSection("AppSettings")).Returns(configurationSection.Object);
var mock1 = new Mock<ICarPairingTable>();
mock1.Setup(p => p.GetDealerId("456")).ReturnsAsync("123");
var mock2 = new Mock<ICarDealerSettingsTable>();
SettingsInfo mockSettings = new SettingsInfo()
{
DealerId = "123",
Name="Dealer1"
};
mock2.Setup(p => p.GetSettingsInfo("123")).ReturnsAsync(()=>mockSettings);
CarController controller = new CarController(mockConfig.Object, mock1.Object, mock2.Object);
var result = controller.Get("456");
//Dont know what to assert
}
Wrote unit test, but not sure if my approach is correct, Help will be appreciated.
This is more of a design issue wrapped in an XY problem.
Really should not be injecting IConfiguration. Based on how the configuration is using by the controller what you should have done was register the settings with the service collection in startup
Startup.ConfigureServices
//...
AppSettings appSettings = Configuration.Get<AppSettingsModel>().AppSettings;
services.AddSingleton(appSettings);
//...
and explicitly inject the settings into the controller
//...
private readonly AppSettings appSettings = null;
public CarController(AppSettings appSettings , ICarPairingTable carPairingTable, ICarDealerSettingsTable settingsTable) {
this.appSettings = appSettings;
PairingTable = carPairingTable;
DealerSettingsTable = settingsTable;
}
//...
So now when unit testing the controller in isolation, you can initialize an instance of the desired class and provide when exercising the unit test.
Reference Explicit Dependencies Principle
You also appear to be mixing async-await and blocking calls like .Result.
I sugest you make the action async all the way
[HttpGet]
public async Task<ActionResult> Get(string id){
string DealerId = await PairingTable.GetDealerId(id);
if (string.IsNullOrEmpty(DealerId)) {
var result = new ReturnResult {
status = "Fail",
data = "ID is invalid"
};
return NotFound(result);
}
SettingsInfo info = await DealerSettingsTable.GetSettingsInfo(DealerId);
if (info == null) {
var result = new ReturnResult {
status = "Fail",
data = "Not Found"
};
return NotFound(result);
}
var result = new ReturnResult {
status = "Success",
data = info
};
return Ok(result);
}
Reference Async/Await - Best Practices in Asynchronous Programming
That way the unit test can finally be arranged correctly to verify the expected behavior
[Fact]
public async Task Should_Return_Ok_ReturnRsult() {
//Arrange
var id = "456";
var dealerId = "123";
SettingsInfo expected = new SettingsInfo() {
DealerId = dealerId,
Name="Dealer1"
};
var pairingMock = new Mock<ICarPairingTable>();
pairingMock.Setup(p => p.GetDealerId(id)).ReturnsAsync(dealerId);
var dealerSettingsMock = new Mock<ICarDealerSettingsTable>();
dealerSettingsMock.Setup(p => p.GetSettingsInfo(dealerId)).ReturnsAsync(() => expected);
CarController controller = new CarController(new AppSettings(), pairingMock.Object, dealerSettingsMock.Object);
//Act
var actionResult = await controller.Get(id);
var actual = actionResult as OkObjectResult;
//Assert (using FluentAssertions)
actual.Should().NotBeNull();
actual.Value.Should().BeOfType<ReturnResult>();
var actualResult = actual.Value as ReturnResult;
actualResult.data.Should().BeEquivalentTo(expected);
}
I'm having a problem working out how and what to test.
I have a controller that injects UserManager and calls the CreateAsync method to create a new user.
I don't want to test the Identity user manager as this has clearly been thoroughly tested already. What I would like to do is test that the controller runs through the correct paths (in my case, there are 3 paths, sending responses back with either model state errors, identity response errors or a simple string)
Should I be trying to create a mock of the user manager in order to create my test (I'm not sure how to set up user manager as a mock dependency)
Second, how can I set conditions to verify that the controller has taken a given path.
I am using xUnit and Moq.
[Route("api/[controller]")]
public class MembershipController : BaseApiController
{
private UserManager<ApplicationUser> _userManager;
public MembershipController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet("RegisterNewUser")]
public HttpResponseMessage RegisterNewUser([FromBody] NewUserRegistration user)
{
if (ModelState.IsValid)
{
ApplicationUser newUser = new ApplicationUser();
newUser.UserName = user.username;
newUser.Email = user.password;
IdentityResult result = _userManager.CreateAsync(newUser, user.password).Result;
if (result.Errors.Count() > 0)
{
var errors = new IdentityResultErrorResponse().returnResponseErrors(result.Errors);
return this.WebApiResponse(errors, HttpStatusCode.BadRequest);
}
}
else
{
var errors = new ViewModelResultErrorResponse().returnResponseErrors(ModelState);
return this.WebApiResponse(errors, HttpStatusCode.BadRequest);
}
return this.WebApiResponse(
"We have sent a valifation email to you, please click on the verify email account link.",
HttpStatusCode.OK);
}
}
In My unit test I have the following to test a happy path scenario
[Fact]
public void RegisterNewUser_ReturnsHttpStatusOK_WhenValidModelPosted()
{
var mockStore = new Mock<IUserStore<ApplicationUser>>();
var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore.Object, null, null, null, null, null, null, null, null);
ApplicationUser testUser = new ApplicationUser { UserName = "user#test.com" };
mockStore.Setup(x => x.CreateAsync(testUser, It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(IdentityResult.Success));
mockStore.Setup(x => x.FindByNameAsync(testUser.UserName, It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(testUser));
mockUserManager.Setup(x => x.CreateAsync(testUser).Result).Returns(new IdentityResult());
MembershipController sut = new MembershipController(mockUserManager.Object);
var input = new NewUserInputBuilder().Build();
sut.RegisterNewUser(input);
}
Where "input" in sut.RegisterNewUser(input); refers to a helper class which constructs the viewmodel which the controller action requires:
public class NewUserInputBuilder
{
private string username { get; set; }
private string password { get; set; }
private string passwordConfirmation { get; set; }
private string firstname { get; set; }
private string lastname { get; set; }
internal NewUserInputBuilder()
{
this.username = "user#test.com";
this.password = "password";
this.passwordConfirmation = "password";
this.firstname = "user";
this.lastname = "name";
}
internal NewUserInputBuilder WithNoUsername()
{
this.username = "";
return this;
}
internal NewUserInputBuilder WithMisMatchedPasswordConfirmation()
{
this.passwordConfirmation = "MismatchedPassword";
return this;
}
internal NewUserRegistration Build()
{
return new NewUserRegistration
{ username = this.username, password = this.password,
passwordConfirmation = this.passwordConfirmation,
firstname = this.firstname, lastname = this.lastname
};
}
}
My aim here is to force 3 conditions via tests:
Create a valid viewmodel and return a success message
Create a valid viewmodel but returns a IdentityResponse error (eg. user exists) which gets converted to
Create an invalid viewmodel and returns Modelstate errors
The errors are handled using a abstract class which returns a json object
The base class for the controller simply constructs a HttpResponseMessage for return.
Basically I want to check that the correct error response class is called by forcing the test down the modelstate error path, the identityresult.errors path and that the happy path can be achieved.
Then my plan is to test the error response classes in isolation.
Hopefully that is enough detail.
Mehod under test should be made async and not use blocking calls ie .Result
[HttpGet("RegisterNewUser")]
public async Task<HttpResponseMessage> RegisterNewUser([FromBody] NewUserRegistration user) {
if (ModelState.IsValid) {
var newUser = new ApplicationUser() {
UserName = user.username,
Email = user.password
};
var result = await _userManager.CreateAsync(newUser, user.password);
if (result.Errors.Count() > 0) {
var errors = new IdentityResultErrorResponse().returnResponseErrors(result.Errors);
return this.WebApiResponse(errors, HttpStatusCode.BadRequest);
}
} else {
var errors = new ViewModelResultErrorResponse().returnResponseErrors(ModelState);
return this.WebApiResponse(errors, HttpStatusCode.BadRequest);
}
return this.WebApiResponse(
"We have sent a valifation email to you, please click on the verify email account link.",
HttpStatusCode.OK);
}
Review of Happy path scenario and method under test shows that there is no need to setup the UserStore as test will be overriding the user manager virtual members directly.
Note the test has also been made async as well.
Create a valid viewmodel and return a success message
[Fact]
public async Task RegisterNewUser_ReturnsHttpStatusOK_WhenValidModelPosted() {
//Arrange
var mockStore = Mock.Of<IUserStore<ApplicationUser>>();
var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null);
mockUserManager
.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
.ReturnsAsync(IdentityResult.Success);
var sut = new MembershipController(mockUserManager.Object);
var input = new NewUserInputBuilder().Build();
//Act
var actual = await sut.RegisterNewUser(input);
//Assert
actual
.Should().NotBeNull()
.And.Match<HttpResponseMessage>(_ => _.IsSuccessStatusCode == true);
}
Create a valid viewmodel but returns a IdentityResponse error (eg. user exists) which gets converted
For this you just need to setup the mock to return a result with errors.
[Fact]
public async Task RegisterNewUser_ReturnsHttpStatusBadRequest_WhenViewModelPosted() {
//Arrange
//...code removed for brevity
mockUserManager
.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
.ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "test"}));
//...code removed for brevity
//Assert
actual
.Should().NotBeNull()
.And.Match<HttpResponseMessage>(_ => _.StatusCode == HttpStatusCode.BadRequest);
}
And for
Create an invalid viewmodel and returns Modelstate errors
You just need to set the model state of the controller so that it is invalid.
[Fact]
public async Task RegisterNewUser_ReturnsHttpStatusBadRequest_WhenInvalidModelState() {
//Arrange
var mockStore = Mock.Of<IUserStore<ApplicationUser>>();
var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null);
var sut = new MembershipController(mockUserManager.Object);
sut.ModelState.AddModelError("", "invalid data");
var input = new NewUserInputBuilder().Build();
//Act
var actual = await sut.RegisterNewUser(input);
//Assert
actual
.Should().NotBeNull()
.And.Match<HttpResponseMessage>(_ => _.StatusCode == HttpStatusCode.BadRequest);
}
FluentAssertions were used to do all the assertions. You could just as easily used Assert.* API.
This should be enough to get you on your way with the above question.
Here's a simple way using NUnit (you could do something similar with xUnit), if you don't want to test the user manager. (I've also shown how the DbContext can be passed to the same controller, using an in-memory database that can be used for setting up mock data)
private DbContextOptions<MyContextName> options;
[OneTimeSetUp]
public void SetUp()
{
options = new DbContextOptionsBuilder<MyContextName>()
.UseInMemoryDatabase(databaseName: "MyDatabase")
.Options;
// Insert seed data into the in-memory mock database using one instance of the context
using (var context = new MyContextName(options))
{
var testWibble = new Wibble { MyProperty = 1, MyOtherProperty = 2 ... };
context.wibbles.Add(testWibble);
context.SaveChanges();
}
}
[Test]
public void Some_TestMethod()
{
// Use a clean instance of the context to run the test
using (var context = new MyDbContext(options))
{
var store = new UserStore<MyUserType>(context);
var userManager = new UserManager<MyUserType>(store, null, null, null, null, null, null, null, null);
MyController MyController = new MyController(userManager, context);
... test the controller
}
}
I'm creating a unit test using nunit and all of this code works fine in runtime.
I have this protected HttpResponseMessage code below that is being called by my controller when it returns.
However, an error:
"Value cannot be null. Parameter name: request" is displaying.
And when I check the request, it is actually null.
Question:
How will I code my unit test to return the HttpResponseMessage?
Error is shown in this line:
protected HttpResponseMessage Created<T>(T result) => Request.CreateResponse(HttpStatusCode.Created, Envelope.Ok(result));
Here is my Controller:
[Route("employees")]
[HttpPost]
public HttpResponseMessage CreateEmployee([FromBody] CreateEmployeeModel model)
{
//**Some code here**//
return Created(new EmployeeModel
{
EmployeeId = employee.Id,
CustomerId = employee.CustomerId,
UserId = employee.UserId,
FirstName = employee.User.FirstName,
LastName = employee.User.LastName,
Email = employee.User.Email,
MobileNumber = employee.MobileNumber,
IsPrimaryContact = employee.IsPrimaryContact,
OnlineRoleId = RoleManager.GetOnlineRole(employee.CustomerId, employee.UserId).Id,
HasMultipleCompanies = EmployeeManager.HasMultipleCompanies(employee.UserId)
});
}
The reason why you are getting:
An exception of type 'System.ArgumentNullException' occurred in System.Web.Http.dll but was not handled in user code
Additional information: Value cannot be null.
is because the Request object is null.
The solution for that is to create an instance of your controller in your tests such as:
var myApiController = new MyApiController
{
Request = new System.Net.Http.HttpRequestMessage(),
Configuration = new HttpConfiguration()
};
In this way, when creating a new instance of the MyApiController class we are initializing the Request object. Moreover, it is also necessary to provide the associated configuration object.
Finally, an example of Unit Test for your Api Controller could be:
[TestClass]
public class MyApiControllerTests
{
[TestMethod]
public void CreateEmployee_Returns_HttpStatusCode_Created()
{
// Arrange
var controller = new MyApiController
{
Request = new System.Net.Http.HttpRequestMessage(),
Configuration = new HttpConfiguration()
};
var employee = new CreateEmployeeModel
{
Id = 1
};
// Act
var response = controller.CreateEmployee(employee);
// Assert
Assert.AreEqual(response.StatusCode, HttpStatusCode.Created);
}
}
I think what happens is that you are not instantiating or assigning your Request property (HttpRequestMessage) when you new up your Controller. I believe it's mandatory to specify the request prior calling into the Api method via your unit test.
You may also require a Configuration (HttpConfiguration):
sut = new YourController()
{
Request = new HttpRequestMessage {
RequestUri = new Uri("http://www.unittests.com") },
Configuration = new HttpConfiguration()
};
Let me know if that works.
Also, if your controller has injections, you can do:
var controller= new MyController(injectionA, injectionB, injectionC)
{
Request = new HttpRequestMessage(),
Configuration = new HttpConfiguration()
};
I find them all on the easy to understand official doc now.
Here's a sample of one of my unit test classes (pared down to the basics). In the controller, when the Index() action method is invoked, a call to GetByID(1234) always results in a newed up instance of a Ticket object. The object exists, but all of its properties are null, even though I've set them in my fake object. Any ideas as to why?
I'm using Moq.
Unit test
[TestClass]
public class TicketControllerTests : ControllerTestBase
{
protected Mock<ITicketRepository> MockTicketRepository = new Mock<ITicketRepository>();
[TestMethod]
public void IndexActionModelIsTypeOfTicketModel()
{
//ARRANGE
Mock<HttpContextBase> context = FakeHttpContext();
context.Setup(ctx => ctx.Session[SessionKeys.TokenData.ToString()]).Returns(Constants.TOKENDATA_SUBMITTER);
MockTicketRepository.Setup(x => x.GetById(It.IsAny<int>())).Returns(Constants.CLIENT_TICKET);
//ACT
var result = GetController(context.Object).Index(Constants.TICKET_ID);
var model = ((ViewResult)result).Model;
//ASSERT
Assert.IsInstanceOfType(model, typeof(TicketModel), "ViewModel should have been an instance of TicketModel.");
}
private TicketController GetController(HttpContextBase context)
{
var controller = new TicketController(MockTicketRepository.Object);
controller.ControllerContext = GetControllerContext(context, controller);
return controller;
}
}
Constants.CLIENT_TICKET
public static Ticket CLIENT_TICKET
{
get
{
var ticket = new Ticket
{
CategoryID = 1,
CreatedByUserId = 4
};
ticket.Clients.Add(new Client { ShortName = "Test Client 1"});
ticket.Clients.Add(new Client { ShortName = "Test Client 2" });
ticket.User = new User {FirstName = "First", LastName = "Last"};
return ticket;
}
}
Controller
private readonly ITicketRepository _ticketRepository;
public TicketController(ITicketRepository ticketRepository)
{
_ticketRepository = ticketRepository;
}
public ActionResult Index(int id)
{
var ticket = _ticketRepository.GetById(id);
// etc...
}
Could you show the controller code under test? It could be related to how you have set up the mocked context but it's hard to tell without seeing the controller code.
Also, if you add MockBehavior.Strict when you create the mock, it will bomb out if the invocation doesn't have a corresponding expectation:
protected Mock<ITicketRepository> MockTicketRepository = new Mock<ITicketRepository>(MockBehavior.Strict);
UPDATE
I've tried to strip everything back so that the test is as simple as possible to try and isolate the issue. Here's what I have come up with:
[TestClass]
public class TicketControllerTests : ControllerTestBase
{
protected Mock<ITicketRepository> MockTicketRepository;
[TestMethod]
public void IndexActionModelIsTypeOfTicketModel()
{
//ARRANGE
MockTicketRepository = new Mock<ITicketRepository>(MockBehavior.Strict);
MockTicketRepository.Setup(x => x.GetById(Constants.TICKET_ID)).Returns(Constants.CLIENT_TICKET);
var controller = new TicketController(MockTicketRepository.Object);
//ACT - try to keep ACT as lean as possible, ideally just the method call you're testing
var result = controller.Index(Constants.TICKET_ID);
//ASSERT
var model = ((ViewResult)result).ViewData.Model;
Assert.That(model, Is.InstanceOfType<TicketModel>(), "ViewModel should have been an instance of TicketModel.")
}
}