Can anyone see where I have went wrong in the following example. I am writing tests to check for an if ID already exists. I have a 'UserService' that calls methods in a generic repository 'RentalsRepository' that makes the calls to the data for me. *Note the code works in the system, just not in my tests
Repo
public class RentalsRepository<T> : IRentalsRepository<T> where T : BaseClass
{
private readonly RentalsDBContext _Context;
private DbSet<T> entities;
string errorMessage = string.Empty;
public RentalsRepository(RentalsDBContext _Context)
{
this._Context = _Context;
entities = _Context.Set<T>();
}
public T Get(string Id)
{
return entities.SingleOrDefault(e => e.Id == Id);
} ...
UserService
public class UserService : IUserService {
private IRentalsRepository<UserAccount> _userRepository;
public UserService(IRentalsRepository<UserAccount> userRepository)
{
this._userRepository = userRepository;
}
public UserAccount GetUserFromId(string id)
{
UserAccount user = _userRepository.Get(id);
user.Email = Encryption.DecryptFromDatabase(user.Email);
return user;
}...
Test Class
[Fact]
public void UserService_GetByID()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring1", Username = "username1"},
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var mockRepo = new Mock<IRentalsRepository<UserAccount>>();
mockRepo.Setup(m => m.Get(It.IsAny<string>())).Returns(mockSet.Object.FirstOrDefault());
var service = new UserService(mockRepo.Object);
UserAccount results = service.GetUserFromId("non-existant");
Assert.Equal("idstring1", results.Id);
}
When I debug I can see the value '"non-existant"' is being used in the method public UserAccount GetUserFromId(string id) but it still somehow returns a user
Latest Attempt
[Fact]
public void UserService_GetUserByUsername()
{
byte[] b = Encryption.GetSalt();
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockContext = new Mock<RentalsDBContext>();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var mockRepo = new Mock<RentalsRepository<UserAccount>>(mockContext.Object);
var testClass = new UserService(mockRepo.Object);
UserAccount results = testClass.GetUserByUsername("username2");
Assert.Equal("username1", results.Username);
}
mockRepo.Setup(m => m.Get(It.IsAny<string>())).Returns(mockSet.Object.FirstOrDefault());
Is going to return the first record in your mock set ("idstring1") no matter what string you pass into Get(). Assuming you get your mocked db context into your repository correctly, there is no reason to mock Get() at all.
Having said that, if you're trying to test if an ID already exists, that's a function of the repository, not your service. All your service is doing is decrypting the email. You're testing both the repository and the service this way, which is not a unit test.
EDIT
We're back to the question of what you are trying to test. If you want to test that the repository retrieves the correct user account, you would mock the db context and use the real repository class.
[Fact]
public void UserRepository_Get()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var testClass = new RentalsRepository<userAccount>(mockContext.Object);
var results = testClass.Get("username2");
Assert.Equal("username2", results.Username);
}
If you want to test that the user service retrieves the user and decrypts the email, you would mock the repository (and it's Get function) and use the real service class.
[Fact]
public void UserService_GetUserByUsername()
{
var userAccount = new UserAccount { Id = "idstring2", Username = "username2", Email = "" };
var mockRepo = new Mock<IRentalsRepository<UserAccount>>();
mockRepo.Setup(m => m.Get("idstring2").Returns(userAccount);
var testClass = new UserService(mockRepo.Object);
var results = testClass.GetUserByUsername("idstring2");
Assert.Equal("idstring2", results.Username);
Assert.AreEqual("???", results.Email);
}
If you want to test both the repository and service together, you certainly can, but it won't be a unit test since you're testing two things at once. In that case, you mock the db context and use real repository and service classes.
[Fact]
public void UserRepository_Get()
{
var users = new List<UserAccount> {
new UserAccount { Id = "idstring2", Username = "username2" },
new UserAccount { Id = "idstring3", Username = "username3" },
}.AsQueryable();
var mockSet = new Mock<DbSet<UserAccount>>();
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<UserAccount>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
var mockContext = new Mock<RentalsDBContext>();
mockContext.Setup(m => m.Set<UserAccount>()).Returns(mockSet.Object);
var repository = new RentalsRepository<userAccount>(mockContext.Object);
var service = new UserService(repository);
var results = service.GetUserByUsername("username2");
Assert.Equal("username2", results.Username);
}
Related
So I've trying to test my webapp coded in .net core 5.0, and I have a classic MVC model with service classes. Now I am trying to unit test the solution with moq to mock my database, and my tests run, but I have just noticed that they are all wrong when I debug. It seems as if it doesn't actually connect to the mock service or database itself... I have gone for mocking the service interface but that doesn't seem to work still. Help would be greatly appreciated.
Service class:
public class InventoryService : IInventoryService
{
private readonly DBContext _db;
public InventoryService(DBContext db)
{
_db = db;
}
public List<Inventory> GetInventories(string id)
{
var inventories = (from i in _db.Inventories where i.userId.Equals(id) select i).ToList();
return inventories;
}
public void CreateInventory(Inventory newInventory)
{
_db.Inventories.Add(newInventory);
_db.SaveChanges();
}
public bool DeleteInventory(Guid Id, string UserId)
{
var inventory = _db.Inventories.Find(Id);
if (inventory == null)
return false;
if (inventory.userId != UserId)
return false;
//Delete items using item service
var items = from i in _db.Items where i.inventoryId.Equals(Id) select i;
foreach(var i in items)
{
_db.Items.Remove(i);
}
_db.Inventories.Remove(inventory);
_db.SaveChanges();
return true;
}
}
}
Service interface it uses:
public interface IInventoryService
{
public List<Inventory> GetInventories(string id);
public void CreateInventory(Inventory newInventory);
public bool DeleteInventory(Guid Id, string UserId);
}
}
Model:
public class Inventory
{
// The Id field is a unique identifier for a specific inventory
[Key]
public Guid Id { get; set; }
// The name of the Inventory. Required to have a value
[Required]
[DisplayName("Inventory Name")]
public string name { get; set; }
public string userId { get; set; }
}
}
Unit test:
public class InventoryTests
{
// Unit test defined for the get user inventories, a valid ID will always be passed in so no need for negative testing
[Fact]
public void Get_user_inventories_with_valid_id()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "Mums 1", userId = u1},
new Inventory { Id = theId1, name = "Mums 1.2", userId = u1},
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
Mock<IInventoryService> myser = new Mock<IInventoryService>();
//ACT
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
var tinvs = myser.Object.GetInventories(u1);
//ASSERT
Assert.Equal(2 , tinvs.Count);
}
//Unit test for creating an inventory, a valid new inventory object will always be passed in so need for negative testing
[Fact]
public void Creating_An_Inventory()
{
//ARRANGE
Guid theId2 = new("00000000-0000-0000-0000-000000000001");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//ACT
Mock<IInventoryService> myser = new Mock<IInventoryService>();
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
Inventory thenew = new Inventory { Id = theId2, name = "Mums 2", userId = u2 };
myser.Object.CreateInventory(thenew);
//ASSERT
Assert.NotNull(data);
}
//Unit test for deleting an inventory. It will always be valid because a guid and user id will be passed in automatically
[Fact]
public void Deleting_An_Inventory()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "123";
//var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "testinv 1", userId = u1},
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//ACT
Mock<IInventoryService> myser = new Mock<IInventoryService>();
myser.Setup(x => x.GetInventories(u1)).Returns(mockSet.Object.ToList());
myser.Object.DeleteInventory(theId1, u1);
var updInvs = myser.Object.GetInventories(u1);
int x = updInvs.Count;
//ASSERT
Assert.Equal(0, x);
}
}
}
I am fairly sure it is a minor error in my setup of the unit test's mocking. any help would be great.
So, if you want to test your InventoryService, you have to mock your dbContext as you do. Better use EF InMemoryDatabase like Microsoft advises https://learn.microsoft.com/en-us/ef/core/testing/#unit-testing
About your tests, I make a few modifications, to test InventoryService. It passes in debug mode.
public class InventoryService : IInventoryService
{
private readonly DBContext _db;
public InventoryService(DBContext db)
{
_db = db;
}
public List<Inventory> GetInventories(string id)
{
//i change inventories to _db.Set<Inventory> which able to be mock
var inventories = (from i in _db.Set<Inventory>() where i.userId.Equals(id) select i).ToList();
return inventories;
}
//ANOTHER CODE
}
[Fact]
public void Get_user_inventories_with_valid_id()
{
//ARRANGE
Guid theId1 = new("00000000-0000-0000-0000-000000000001");
Guid theId2 = new("00000000-0000-0000-0000-000000000002");
string u1 = "xxx";
string u2 = "yyy";
var mockIn = new Mock<IInventoryService>();
var data = new List<Inventory>
{
new Inventory { Id = theId1, name = "Mums 1", userId = u1 },
new Inventory { Id = theId1, name = "Mums 1.2", userId = u1 },
}.AsQueryable();
var mockSet = new Mock<DbSet<Inventory>>();
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Inventory>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
//HERE
var dbMock = new Mock<DBContext>();
dbMock.Setup(x => x.Set<Inventory>()).Returns(mockSet.Object);
var myser = new InventoryService(dbMock.Object);
//ACT
//AND HERE
var tinvs = myser.GetInventories(u1);
//ASSERT
Assert.Equal(2, tinvs.Count);
}
If you want to make InMemory db or test on real SQL db, you look at these questions.
Unit testing EF Core using in-memory database with an eager-loaded function
Unit testing with EF Core and in memory database
I am failing on the BeUniqueEmail with the error message (below). How can I mock this correctly? I have included the validator and the test below.
The tests passed when I removed the BeUnique email validation
Message:
System.NotImplementedException : The method or operation is not implemented.
public class CreateStudentCommandValidator : AbstractValidator<CreateStudentCommand>
{
private readonly IApplicationDbContext _context;
public CreateStudentCommandValidator(IApplicationDbContext context)
{
_context = context;
RuleFor(v => v.Email)
.NotEmpty().WithMessage("Email is required.")
.MaximumLength(30).WithMessage("Email must not exceed 30 characters.")
.MustAsync(BeUniqueEmail).WithMessage("The specified email already exists.");
}
public async Task<bool> BeUniqueEmail(CreateStudentCommand model, string email, CancellationToken cancellationToken)
{
bool emailExists = await _context.Students
.Where(x => x.Email == email)
.Where(x => !x.IsDeleted)
.CountAsync() > 0;
return !emailExists;
}
}
Testing
[Test]
public async Task CreateStudentCommand_Success()
{
var mockSet = new Mock<DbSet<Student>>();
var context = new Mock<IApplicationDbContext>();
context.Setup(m => m.Student).Returns(mockSet.Object);
var handler = new CreateStudentCommandHandler(context.Object);
var validator = new CreateStudentCommandValidator(context.Object);
//var mockedValidator = new Mock<IValidator<CreateStudentCommandValidator>>();
//var mock1 = new Mock<AbstractValidator<CreateStudentCommandValidator>>();
var command = new CreateStudentCommand
{
StudentType = "Test1",
Email = "Test1#email.com",
FirstName = "Test1",
LastName = "Test1",
IsActive = true
};
var result = await handler.Handle(command, new CancellationToken());
// Act
var validationResult = await validator.ValidateAsync(command);
// Assert
Assert.True(validationResult.IsValid);
Assert.IsInstanceOf<Guid>(result);
}
Using Moq, a solution to this could be as follows.
[Test]
public async Task TestValidation()
{
var context = Mock.Of<ApplicationDbContext>();
var validator = new CreateStudentCommandValidator(context);
var command = new CreateStudentCommand
{
StudentType = "Test1",
Email = "Test1#email.com",
FirstName = "Test1",
LastName = "Test1",
IsActive = true
};
var validationResult = await validator.ValidateAsync(command);
Assert.True(validationResult.IsValid);
}
Not knowing your Context, I implemented a simple dummy.
public interface IApplicationDbContext
{
List<Student> Students { get; set; }
}
public class ApplicationDbContext : IApplicationDbContext
{
public ApplicationDbContext()
{
Students = new List<Student>();
}
public List<Student> Students { get; set; }
}
This all depends on the use of Moq however, If you are using some other Mocking Service the Implementation will change.
*My Previous answer was intended to explain the implementation of Mocking Method Results. But in this case you do not need to mock the CreateStudentCommandValidator
I'm new in writing tests and Mock. I'm trying to figure it out how to mock Raw SQL to retrieve data. Here's what I have:
I have DataContext.cs
public class DataContext : DbContext
{
public DataContext()
: base("Main")
{
}
public virtual DbSet<DbBook> Books { get; set; }
public virtual DbSet<DbMovie> Movies { get; set; }
}
I have controller BooksController.cs
public class BooksController : ApiController
{
private readonly BookDataContext _db;
public BooksController ()
{
_db = new BookDataContext();
}
public BooksController (BookDataContext context)
{
_db = context;
}
[HttpGet]
[Route("books")]
public Book GetBooks()
{
using (var dbContextTransaction = _db.Database.BeginTransaction())
{
var test = _db.Books.SqlQuery("select * from BOOK");
var test2 = from b in _db.Books
orderby b.Books
select b;
}
}
}
And I have test
[TestMethod]
public void GetBook()
{
var data = new List<DbBook>
{
new DbBook{ Book = "Book1"},
new DbBook{ Book = "Book2"}
}.AsQueryable();
var mockSet = new Mock<DbSet<DbScriptId>>();
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<DbBook>>().Setup(m =>
m.GetEnumerator()).Returns(data.GetEnumerator());
mockSet.Setup(m => m.Find(It.IsAny<object[]>()))
.Returns<object[]>(sc => data.SingleOrDefault());
var mockContext = new Mock<DataContext>();
mockContext.Setup(c => c.Books).Returns(mockSet.Object);
var controller = new BooksController (mockContext.Object);
var books = controller.GetBook();
}
I can retrieve data using Linq (test2) but using SqlQuery I always get null (test). How to change that using SqlQuery I get same result as using Linq? Also I'm getting to know that creating InMemory database actually creates some lists (type=IQueriable) in background, not database. Can you please provide some explanation and resolution for this issue?
How about this. (not sure if I understand your question right)
var queryMock = new Mock<DbSqlQuery<DbBook>>();
queryMock.Setup(x => x.GetEnumerator()).Returns(data.GetEnumerator());
mockSet.Setup(m => m.SqlQuery(It.IsAny<string>(), It.IsAny<object[]>())).Returns(queryMock.Object);
This example assumes that all queries will return all items.
This question already has answers here:
How to mock an async repository with Entity Framework Core
(9 answers)
Closed 3 years ago.
I have this test:
[Fact]
public async void Can_Paginate()
{
//fake data
var product1 = new Product { ProductId = 1, ProductName = "P1" };
var product2 = new Product { ProductId = 2, ProductName = "Product 2" };
var product3 = new Product { ProductId = 3, ProductName = "Product 3" };
var product4 = new Product { ProductId = 4, ProductName = "Product 4" };
var product5 = new Product { ProductId = 5, ProductName = "Product 5" };
var data = new List<Product>
{
product1,
product2,
product3,
product4,
product5
}.ToAsyncEnumerable();
var category1 = new Category { CategoryId = 1 };
var prodCategoryData = new List<ProductCategory>
{
new ProductCategory { Product =product1,Category = category1},
new ProductCategory { Product =product2,Category = category1},
new ProductCategory { Product =product3,Category = category1},
new ProductCategory { Product =product4,Category = category1},
new ProductCategory { Product =product5,Category = category1}
}.ToAsyncEnumerable();
var dbSetMock = new Mock<DbSet<Product>>();
//dbSetMock.As<IQueryable<Product>>().Setup(m => m.Provider).Returns(data.Provider);
//dbSetMock.As<IQueryable<Product>>().Setup(m => m.Expression).Returns(data.Expression);
//dbSetMock.As<IQueryable<Product>>().Setup(m => m.ElementType).Returns(data.ElementType);
//dbSetMock.As<IQueryable<Product>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var pcDbSetMock = new Mock<DbSet<ProductCategory>>();
// pcDbSetMock.As<IQueryable<ProductCategory>>().Setup(m => m.Provider).Returns(prodCategoryData.Provider);
//pcDbSetMock.As<IQueryable<ProductCategory>>().Setup(m => m.Expression).Returns(prodCategoryData.Expression);
//pcDbSetMock.As<IQueryable<ProductCategory>>().Setup(m => m.ElementType).Returns(prodCategoryData.ElementType);
//pcDbSetMock.As<IQueryable<ProductCategory>>().Setup(m => m.GetEnumerator()).Returns(prodCategoryData.GetEnumerator());
Mock<ApplicationDbContext> customDbContextMock = new Mock<ApplicationDbContext>();
customDbContextMock.Setup(x => x.Products).Returns(dbSetMock.Object);
customDbContextMock.Setup(x => x.ProductCategories).Returns(pcDbSetMock.Object);
var loggerMock = new Mock<ILogger<ProductsController>>();
var envMock = new Mock<IHostingEnvironment>();
var httpContext = new Mock<HttpContext>().Object;
var actionDescriptor = new Mock<Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor>().Object;
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new Mock<RouteData>().Object, actionDescriptor, modelState);
ProductsController controller = new ProductsController(customDbContextMock.Object, loggerMock.Object, envMock.Object);
controller.pageSize = 3;
controller.ControllerContext = new ControllerContext(actionContext);
var result = await controller.List(1, 2);
My controller logic:
public async Task<IActionResult> List(int Id, int page = 1)
{
if (Id == 0)
{
ViewBag.CategoryName = "Wszystkie produkty";
return View(await _context.ProductCategories.Include(c => c.Product).ToListAsync());
}
return View(await _context.ProductCategories
.Include(p => p.Product)
.Where(pt => pt.CategoryId == Id)
.OrderBy(p=>p.ProductId)
.Skip((page-1)*pageSize)
.ToListAsync());
}
My problem is that I cannot mock _context.ProductCategories by using prodCategoryData and data lists as IAsyncEnumerable.
When I cast them to IQueryable I get this error instead:
Additional information: The source IQueryable doesn't implement IAsyncEnumerable<WineCom.Models.ProductCategory>. Only sources that implement IAsyncEnumerable can be used for Entity Framework .
Using the test classes from this answer :
How to mock an async repository with Entity Framework Core
The following generic extension method was derived
public static Mock<DbSet<T>> ToAsyncDbSetMock<T>(this IEnumerable<T> source)
where T : class {
var data = source.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IAsyncEnumerable<T>>()
.Setup(m => m.GetEnumerator())
.Returns(new TestAsyncEnumerator<T>(data.GetEnumerator()));
mockSet.As<IQueryable<T>>()
.Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<T>(data.Provider));
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator());
return mockSet;
}
With the above extension method the test can be refactored to
[Fact]
public async Task Can_Paginate() {
//Arrange
var products = GetFakeProducts().ToAsyncDbSetMock();
var productCategories = GetFakeProductCategories().ToAsyncDbSetMock();
var customDbContextMock = new Mock<ApplicationDbContext>();
customDbContextMock.Setup(x => x.Products).Returns(products.Object);
customDbContextMock.Setup(x => x.ProductCategories).Returns(productCategories.Object);
//...other code removed for brevity
var controller = new ProductsController(customDbContextMock.Object, loggerMock.Object, envMock.Object);
controller.pageSize = 3;
controller.ControllerContext = new ControllerContext(actionContext);
//Act
var result = await controller.List(1, 2);
//Assert
//...other code removed for brevity
}
I am trying to write a unit test but encountered a strange problem
[TestMethod]
public void Delete_user_save_via_context()
{
var data = new List<admins>
{
new admins() {id = 1, login = "test" },
}.AsQueryable();
var mockSet = new Mock<DbSet<admins>>(data);
mockSet.As<IQueryable<admins>>().Setup(x => x.Provider).Returns(data.Provider);
mockSet.As<IQueryable<admins>>().Setup(x => x.Expression).Returns(data.Expression);
mockSet.As<IQueryable<admins>>().Setup(x => x.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<admins>>().Setup(x => x.GetEnumerator()).Returns(data.GetEnumerator);
var mockContext = new Mock<Entities>();
mockContext.Setup(x => x.admins).Returns(mockSet.Object); //Here i have Exception
var userService = new UserService(mockContext.Object);
userService.Delete("test");
mockSet.Verify(m => m.Remove(It.IsAny<admins>()),Times.Once);
mockContext.Verify(m => m.SaveChanges(), Times.Once);
}
This throws exception :
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException: Can not
instantiate proxy of class: Could not find a constructor that would
match given arguments: System.Linq.EnumerableQuery`
Can somebody help with this ?
Implementation of admin class :
public partial class admins
{
public int id { get; set; }
public string login { get; set; }
}
var mockSet = new Mock<DbSet<admins>>(data);
Should be:
var mockSet = new Mock<DbSet<admins>>();