I was trying to set up my Moq for WebApi unit testing, but Assert.IsNotNull(contentResult) is always failed. Is that becasue I pass my mockList incorrectly? Please help me, code as belowed
[TestMethod]
public void GetCEO()
{
// setting up the mock framework
var mockRepository = new Mock<IUsersRepository>();
List<Users> mockList = new List<Users>();
{
new Users
{
User = 1,
FirstName = "TestFirstName",
LastName = "TestLastName",
Group = "CEO"
};
}
mockRepository
.Setup(x => x.GetCEOs())
.Returns(mockList);
var controller = new UsersController(mockRepository.Object);
IHttpActionResult actionResult = controller.Get();
var contentResult = actionResult as OkNegotiatedContentResult<IEnumerable<Users>>;
Assert.IsNotNull(mockList);
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Content);
var users = contentResult.Content;
Assert.AreEqual(1, users.Count());
}
Please check my get action method
[HttpGet]
[Route("api/GetCEO")]
public IHttpActionResult Get()
{
var data=_repository.GetCEOs();
if (data == null)
return NotFound();
else
return Ok(data);
}
My IusersRepositoy
public interface IUsersRepository
{
List<Users> GetUsers(int supervisor);
List<Users> GetCEOs();
}
That's cause the as casting is failing and resulting in null
actionResult as OkNegotiatedContentResult<IEnumerable<Users>>
There is issue. per your edit your method definition is below
List<Users> GetCEOs();
With that you should cast to
actionResult as OkNegotiatedContentResult<List<Users>>
Yeah that's cause your code is full of error. It should be like below
List<Users> mockList = new List<Users>()
{
new Users
{
User = 1,
FirstName = "TestFirstName",
LastName = "TestLastName",
Group = "CEO"
}
};
mockRepository
.Setup(x => x.GetCEOs())
.Returns(mockList);
Related
I am trying to test a controller in my asp.netcore application. The test is failing because of auto-mapper.
I tried to mock to the auto-mapper but i do not know how to use it correctly.
Would anyone be able to suggest a way of overcoming this?
Thanks.
BooksController.cs
[HttpGet("{id:int}")]
public IActionResult GetBook(int id)
{
var bookfromRepo = _repository.GetBook(id);
var book = Mapper.Map<BookDto>(bookfromRepo);
return Ok(book);
}
startup.cs
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<Data.Database.Entities.Book, BookDto>();
});
ControllerTest.cs
[Fact(DisplayName = "GetBook")]
public void GetBook()
{
//act
var fakerepository = new Mock<IBPDRepository>();
var sut = new BooksController(fakerepository.Object);
//act
var book = new BookDto();
var viewModelBook = new BookDto {
Id = 1,
Name = "C#",
Review = "good",
Pages = "500",
Rating = "8",
Price ="$10.00"
};
//var mockMapper = new Mock //stuck here;
sut.GetBook(1);
//assert
IActionResult actionResult = sut.GetBook(2);
Assert.Equal("C#",viewModelBook.Name);
}
Change your Mapper to an IMapper, and then you can write something like that for the UnitTest :
(I'm doing that free-hand, so there might be slight adjustments to make)
[Fact(DisplayName = "GetBook")]
public void GetBook()
{
// Arrange
var mockBook1 = new Mock<BookDto>(Behavior = MockBehavior.Strict);
var mockBook2 = new Mock<BookDto>(Behavior = MockBehavior.Strict);
var mockRepository = new Mock<IBPDRepository>(Behavior = MockBehavior.Strict);
mockRepository.Setup(r => r.GetBook(It.Is<int>(1)).Returns(mockBook1.Object)
var mockMapper = new Mock<IAutoMapper>(Behavior = MockBehavior.Strict);
mockMapper.Setup(m => m.Map<BookDto>(mockBook1.Object)).Returns(mockBook2.Object);
// You might have to change the constructor.
var sut = new BooksController(mockRepository.Object, mockMapper.Object);
IActionResult actionResult;
// Act
actionResult = sut.GetBook(1);
var actualBook = actionResult.Model as BookDto;
// Assert
Assert.Equal(mockBook2.Object, actualBook);
}
The reason why I'd use mockBook rather than straight BookDto is that this way, combined with the Strict behavior, you know the method didn't change anything on it since you did no setup on it.
I am trying to mock ApplicationUserManager.Users so that I can test a controller method. My controller is
public class ManageController : Controller
{
private readonly ApplicationUserManager userManager;
public ManagerController(ApplicationUserManager userManager)
{
this.userManager = userManager;
}
// The method being tested
public ActionResult ListUsers()
{
// I want this to return my mocked user list
var users = this.userManager.Users.ToList();
// Do other stuff
}
}
My test method is
[TestMethod]
public void ListUsersGet_ShouldSucceed()
{
var users = new List<ApplicationUser>
{
new ApplicationUser { Id = "1", FirstName = "Test", LastName = "User" }
}.AsQueryable();
Mock<DbSet<ApplicationUser>> dbSet = new Mock<DbSet<ApplicationUser>>();
dbSet.As<IQueryable<ApplicationUser>>().Setup(e => e.ElementType).Returns(users.ElementType);
dbSet.As<IQueryable<ApplicationUser>>().Setup(e => e.Expression).Returns(users.Expression);
dbSet.As<IQueryable<ApplicationUser>>().Setup(e => e.GetEnumerator()).Returns(users.GetEnumerator());
dbSet.As<IQueryable<ApplicationUser>>().Setup(e => e.Provider).Returns(users.Provider);
Mock<MyContext> context = new Mock<MyContext>();
context.Setup(e => e.Users).Returns(dbSet.Object);
Mock<UserStore<ApplicationUser>> userStore = new Mock<UserStore<ApplicationUser>>(context.Object);
var controller = new ManageController(new ApplicationUserManager(userStore.Object));
var result = controller.ListUsers() as ViewResult;
// Assert some stuff
}
When I step into my controller method, I can see that users is null. It appears that this.userManager.Users isn't returning the users that I tried to set up in my test method.
How can I get this.userManager.Users.ToList() to return my test users?
User manager exposes public virtual IQueryable<TUser> Users { get; } property. Mock the user manager dependency and give that to the controller.
public void _ListUsersGet_ShouldSucceed() {
// Arrange.
var users = new List<ApplicationUser>
{
new ApplicationUser { Id = "1", FirstName = "Test", LastName = "User" }
}.AsQueryable();
//Only mocking this because we need it to initialize manager.
var userStore = Mock.Of<IUserStore<ApplicationUser>>();
var userManager = new Mock<ApplicationUserManager>(userStore);
userManager.Setup(_ => _.Users).Returns(users);
var controller = new ManageController(userManager.Object);
// Act.
var result = controller.ListUsers() as ViewResult;
// Assert some stuff
}
Check the Quick start documentation to get more acquainted with the mocking framework
I am fairly new to unit testing and I am trying to create a unit test for a Web API contoller that I have created which returns a list of brands.
My Web API controller Get() method looks like this:
[HttpGet("/api/Brands/Get", Name = "GetBrands")]
public async Task<IActionResult> Get()
{
var brands = await _brandsService.GetAll(null, "Image");
return Json(brands);
}
The generic service method looks like this:
public async Task<List<T>> GetAll(
Func<IQueryable<T>,
IOrderedQueryable<T>> orderBy = null,
string includeProperties = null)
{
return await _genericRepository.GetAll(orderBy, includeProperties);
}
and the generic repo method looks like this:
public async Task<T> Get<TKey>(Expression<Func<T, bool>> filter = null, string includeProperties = "", bool noTracking = false)
{
includeProperties = includeProperties.Trim() ?? string.Empty;
IQueryable<T> query = Context.Set<T>();
if (noTracking)
{
query.AsNoTracking();
}
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
return await query.SingleOrDefaultAsync();
}
This is working and I am returning a list of brands from the database.
Now I tried to create a Unit test for this:
[SetUp]
public void Setup()
{
Brands = new List<Brand>
{
new Brand
{
Id = 1,
Name = "Adidas",
ImageId = 1
},
new Brand
{
Id = 2,
Name = "Nike",
ImageId = 2
},
new Brand
{
Id = 3,
Name = "Puma",
ImageId = 3
}
};
}
[Test]
public async Task Get_ReturnsAAListOfBrands()
{
//Arrange
var mockService = new Mock<IGenericService<Brand>>();
mockService.Setup(repo => repo.GetAll(null, null)).Returns(Task.FromResult(Brands));
var controller = new BrandsController(mockService.Object);
//Act
var result = await controller.Get();
//Assert
}
however the result is always null. Am I testing this correctly or do I need to change my unit test code to verify that the mock service has three items stored?
You need to configure the setup to expect a particular behavior or argument for the test.
In this case using the It.IsAny<T>() to tell the set up what to expect in terms of arguments will allow the test to flow as desired.
Given that the GetAll method requires two parameters of
Func<IQueryable<T>, IOrderedQueryable<T>> and string, the setup configures what to do based on the values entered for those parameters.
[Test]
public async Task Get_ReturnsAAListOfBrands() {
//Arrange
var mockService = new Mock<IGenericService<Brand>>();
mockService
.Setup(repo => repo.GetAll(It.IsAny<Func<IQueryable<Brand>, IOrderedQueryable<Brand>>>(), It.IsAny<string>()))
.ReturnsAsync(Brands);
var controller = new BrandsController(mockService.Object);
//Act
var result = await controller.Get();
//Assert
//...
}
Take a look at the Moq Quickstart for a better understanding of how to use this mocking framework
So, I'm starting to learn an implement UniTesting on a Web Api project I'm working on. What's happening is that when I setup a mock a call this one returns null instead of the value I'm telling to returns. I don't know why a similiar Setup works but this one just doesn't.
Here is my Test Class
namespace API.Tests.Web
{
[TestClass]
public class MaterialsControllerTest
{
private MaterialsController controller;
private Mock<IRTWRepository> repository;
private Mock<IModelFactory> factory;
private Mock<IRTWAPIIdentityService> identityService;
List<MaterialAccepted> materials;
MaterialAccepted material;
[TestInitialize]
public void Initialize()
{
repository = new Mock<IRTWRepository>();
factory = new Mock<IModelFactory>();
identityService = new Mock<IRTWAPIIdentityService>();
controller = new MaterialsController(repository.Object);
material = new MaterialAccepted()
{
business = true,
businessService = EnumRecycleCenterService.Dropoff,
residential = false,
residentialService = EnumRecycleCenterService.Pickup,
note = "this a note",
Category = new Category()
{
name = "Books"
}
};
materials = new List<MaterialAccepted>()
{
new MaterialAccepted() { business=true,businessService=EnumRecycleCenterService.Dropoff,residential=false,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
new MaterialAccepted() { business=false,businessService=EnumRecycleCenterService.Dropoff,residential=true,residentialService=EnumRecycleCenterService.Pickup,note="this a note"},
};
}
[TestMethod]
public void Post_ShouldReturnBadRequestWhenMaterialAcceptedModelValidationFails()
{
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Assert.IsInstanceOfType(actionResult, typeof(BadRequestResult));
}
}
}
Here is the action in the Controller I'm trying to test
[HttpPost]
[Route("api/recyclecenters/{rcid}/materials/")]
public IHttpActionResult Post(int rcid, [FromBody]MaterialAcceptedModel model)
{
try
{
if (model != null)
{
var recycleCenter = TheRepository.RecycleCenterRepository.Get(rcid);
if (recycleCenter == null)
return NotFound();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var entity = TheModelFactory.Parse(model);
if (entity == null) return BadRequest("Could not read material accepted in body");
if (TheRepository.MaterialAcceptedRepository.Get(recycleCenter.RecycleCenterId, entity.Category.name) != null)
return Conflict();
recycleCenter.Materials.Add(entity);
if (TheRepository.SaveAll())
{
string locationHeader = Url.Link("Materials", new { rcid = rcid, name = model.category.ToLower() });
return Created<MaterialAcceptedModel>(locationHeader, TheModelFactory.Create(entity));
}
return BadRequest("Could not save to the database");
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
If I run this test it will fail because it returns an instancy type of NotFoundResult instead of a BadRequestResult, and this is happening because the test method stops in this line
if (recycleCenter == null)
return NotFound();
But this test it suppose to stop on this line
if (!ModelState.IsValid)
return BadRequest(ModelState);
Any ideas why this
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
is returning null when it should return a new RecycleCenter
It seems like you are setting up the repository mock for rcid = 3, and calling the repository in the controller with rcid = 2.
//arrange
repository.Setup(r => r.RecycleCenterRepository.Get(3)).Returns(() => new RecycleCenter());
controller.ModelState.AddModelError("error", "unit test error");
//act
var actionResult = controller.Post(2, new MaterialAcceptedModel());
Try calling it with rcid = 3
var actionResult = controller.Post(3, new MaterialAcceptedModel());
or change the Moq setup parameter to It.IsAny<int>()
In our MVC4 application with Entity Framework 4.0 based on the Music Store Tutorial we are using Moq to mock the DbContext and unit test are logic. One of our methods proves difficult to test though since it makes use of HttpContext or HttpContextBase. One example method looks like this:
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
The only property collected from HttpContextBase is the [CartSessionKey] as can be seen here:
public string GetCartId(HttpContextBase context)
{
if (context.Session[CartSessionKey] == null)
{
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
context.Session[CartSessionKey] =
context.User.Identity.Name;
}
else
{
// Generate a new random GUID using System.Guid class
Guid tempCartId = Guid.NewGuid();
// Send tempCartId back to client as a cookie
context.Session[CartSessionKey] = tempCartId.ToString();
}
}
return context.Session[CartSessionKey].ToString();
}
We have heard horror stories that HttpContext is a very complex class and that if you print it you have enough paper to circle the earth eight times.
Nevertheless we want to mock it. The question is how. The properties that we want to mock are the [CartSessionKey], and the property that come from the context as contest.User.Identity.Name.
We suspect we need to use something like this:
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
mockData.Setup(m => m.Carts).Returns(memoryCartItems);
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
Mock<HttpRequestBase> mockHttpRequest = new Mock<HttpRequestBase>();
mockHttpRequest.Setup(x => x.CartSessionKey).Returns(1);
mockHttpContext.Setup(x => x.Request).Returns(mockHttpRequest.Object);
but we cannot find how to specifically implement this so we do not get any errors on methods that use context.Session[CartSessionKey] or context.User.Identity.Name.
We hope someone can help us out.
/edit
When we do this:
var memoryUserItems = new FakeDbSet<User>()
{
new User { Email = "test#test.de",
FullName = "Test Person",
isAvailable = true,
Name = "WHat"
},
new User { Email = "test2#test.de",
FullName = "Test Person 2",
isAvailable = true,
Name = "WHat 2"
}
};
(...) Other memory...Items
And then this:
// Create mock units of work
var mockData = new Mock<FakeContext>();
mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
mockData.Setup(m => m.Carts).Returns(memoryCartItems);
mockData.Setup(m => m.Users).Returns(memoryUserItems);
var principalMock = new Mock<IPrincipal>();
var identityMock = new Mock<IIdentity>();
var userMock =
identityMock.Setup(x => x.Name).Returns("Test!");
identityMock.Setup(x => x.IsAuthenticated).Returns(true); // optional ;)
mockData.Setup(x => x.Identity).Returns(identityMock.Object);
var httpReqBase = new Mock<HttpRequestBase>(); // this is useful if you want to test Ajax request checks or cookies in the controller.
var httpContextBase = new Mock<HttpContextBase>();
httpContextBase.Setup(x => x.User).Returns(principalMock.Object);
httpContextBase.Setup(x => x.Session[It.IsAny<string>()]).Returns(1); //Here is the session indexer. You can swap 'any' string for specific string.
httpContextBase.Setup(x => x.Request).Returns(httpReqBase.Object);
We get the error that:
Error 3 'project.Models.FakeContext' does
not contain a definition for 'Identity' and no extension method
'Identity' accepting a first argument of type
'project.Models.FakeContext' could be found
(are you missing a using directive or an assembly
reference?)
/ edit2
To make it more clear. The actual method I am testing is the following:
public ActionResult Complete(int id)
{
// Make sure that user is currentuser and otherwise bring user to our Thief page
if (id != db.GetCurrentUserId())
{
return View("Thief");
}
var cart = ShoppingCart.GetCart(this.HttpContext);
var currentDate = DateTime.Today;
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal(),
ProductItems = db.Products.ToList()
};
if (viewModel.CartItems.Count() == 0)
{
return View("Empty");
}
// Try to write cart to order table
try
{
foreach (var item in viewModel.CartItems)
{
ProcessOrder(item, id, currentDate);
}
// after this we empty the shopping cart
cart.EmptyCart();
return View();
}
catch
{
// Invalid - display error page
return View("Error");
}
}
As can be seen the var cart = ShoppingCart.GetCart(this.HttpContext); uses this.HttpContext. In the test I just do controller.Complete(1). I cannot pass a new HttpContext to the controller I guess?
/ edit 3
While using the code below with the mocks I get the following message:
Test Name: TestCheckoutCompleteShouldWithEmptyCart
Test FullName: Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart
Test Source: Controllers\CheckoutControllerTest.cs : line 141
Test Outcome: Failed
Test Duration: 0:00:00.0158591
Result Message:
Test method Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:
at Models\ShoppingCart.cs:line 170
at \Models\ShoppingCart.cs:line 20
at \Controllers\CheckoutController.cs:line 48
at Controllers\CheckoutControllerTest.cs:line 143
OK, here it goes. The following works in MVC5 with AD, I'm not sure if it's fully backwards compatible, you'll have to check.
var principalMock = new Mock<IPrincipal>();
var identityMock = new Mock<IIdentity>();
identityMock.Setup(x => x.Name).Returns("Test!");
identityMock.Setup(x => x.IsAuthenticated).Returns(true); // optional ;)
userMock.Setup(x => x.Identity).Returns(identityMock.Object);
var httpReqBase = new Mock<HttpRequestBase>(); // this is useful if you want to test Ajax request checks or cookies in the controller.
var httpContextBase = new Mock<HttpContextBase>();
httpContextBase.Setup(x => x.User).Returns(principalMock.Object);
httpContextBase.Setup(x => x.Session[It.IsAny<string>()]).Returns(1); //Here is the session indexer. You can swap 'any' string for specific string.
httpContextBase.Setup(x => x.Request).Returns(httpReqBase.Object);
This would help you to write a proper Unit Test using Moq.
[TestClass]
public class SutTest
{
[TestMethod]
public void GetCartId_WhenUserNameIsNotNull_SessionContainsUserName()
{
var httpContextStub = new Mock<HttpContextBase>();
var httpSessionStub = new Mock<ISessionSettings>();
httpSessionStub.Setup(x => x.Get<string>(It.IsAny<string>())).Returns(() => null);
httpSessionStub.SetupSequence(x => x.Get<string>(It.IsAny<string>()))
.Returns(null)
.Returns("FakeName");
var httpUserStub = new Mock<IPrincipal>();
var httpIdenttyStub = new Mock<IIdentity>();
httpUserStub.SetupGet(x => x.Identity).Returns(httpIdenttyStub.Object);
httpIdenttyStub.SetupGet(x => x.Name).Returns("FakeName");
httpContextStub.Setup(x => x.User).Returns(httpUserStub.Object);
var sut = new Sut(httpSessionStub.Object);
var result = sut.GetCartId(httpContextStub.Object);
Assert.AreEqual("FakeName",result );
}
}
Check the SetupSequence method which gives you find Control over different values being return on he same stubbed call.
Also important to decouple your session from HttpContext as you can always run into issues.
public class SessionSettings : ISessionSettings
{
private readonly HttpSessionStateBase _session;
public SessionSettings(HttpSessionStateBase session)
{
_session = session;
}
public T Get<T>(string key)
{
return (T)_session[key];
}
public void Set<T>(string key, T value)
{
_session[key] = value;
}
}
public interface ISessionSettings
{
T Get<T>(string key);
void Set<T>(string key, T value);
}
public class Sut
{
private ISessionSettings _sessionSettings;
public Sut(ISessionSettings sessionSettings)
{
_sessionSettings = sessionSettings;
}
public string GetCartId(HttpContextBase context)
{
if (_sessionSettings.Get<string>(CartSessionKey) == null)
{
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
_sessionSettings.Set<string>(CartSessionKey, context.User.Identity.Name);
}
else
{
// Generate a new random GUID using System.Guid class
Guid tempCartId = Guid.NewGuid();
// Send tempCartId back to client as a cookie
_sessionSettings.Set<string>(CartSessionKey, tempCartId.ToString());
}
}
return _sessionSettings.Get<string>(CartSessionKey);
}
private string CartSessionKey = "key";
}
This way the code is more readable and easier to understand.