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
}
Related
I have my interface as below
public interface IAssessmentDbContext
{
DatabaseFacade Database { get; }
DbSet<Domain.Entities.Assessment> Assessments { get; }
DbSet<AssessmentType> AssessmentTypes { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
DbSet<AssessmentType> GetAssessmentTypes();
}
and i'm trying to mock data as follows.
public class AssessmentsControllerTests
{
private readonly IFixture _fixture;
private readonly Mock<IAssessmentDbContext> dbContextMock;
private readonly Mock<IRequestClient<GetCandidates>> requestClientMock;
private readonly AssessmentsController controller;
//private readonly Mock<CancellationToken> cancellationTokenMock;
public AssessmentsControllerTests()
{
dbContextMock = _fixture.Freeze<Mock<IAssessmentDbContext>>();
var data1 = new List<Domain.Entities.AssessmentType>();
var data = new Domain.Entities.AssessmentType()
{
Id = new Guid("CD4FA15F-B882-4995-57A3-08DA9A133B59"),
AssessmentTypeName = "Big50",
AssessmentTypeText = "Big Fifty"
};
data1.Add(data);
DbSet<Domain.Entities.AssessmentType> myDbSet = GetQueryableMockDbSet(data1);
var dataAssessment = new List<Domain.Entities.Assessment>();
Domain.Entities.Assessment obj = new Domain.Entities.Assessment()
{
AssessmentTypeId = new Guid("CD4FA15F-B882-4995-57A3-08DA9A133B59"),
UserId = new Guid("1572EA1B-4CBD-4C05-D03C-08DA47BC4FD9"),
CreatedAt = DateTime.Now,
Id = Guid.NewGuid()
};
dataAssessment.Add(obj);
DbSet<Domain.Entities.Assessment> myDbSetAssessment = GetQueryableMockDbSet(dataAssessment);
dbContextMock.Setup(x=>x.GetAssessmentTypes()).Returns(myDbSet);
dbContextMock.Setup(x => x.Assessments).Returns(myDbSetAssessment);
controller = new AssessmentsController(dbContextMock.Object);
}
[Fact]
public void GetAssessments_ShouldReturnData_WhenWithUserId()
{
// Arrange
var userIdMock = _fixture.Create<Guid>();
CancellationToken token = _fixture.Create<CancellationToken>();
// Act
var result = controller.GetAssessments("1572EA1B-4CBD-4C05-D03C-08DA47BC4FD9", token);
// Assert
result.Should().NotBeNull();
result.Should().BeAssignableTo<IActionResult>();
}
private static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s));
return dbSet.Object;
}
}
}
How can I mockup both Assessments and AssessmentType in IAssessmentDbContext
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
is there a way to store the select clause of a linq statement as a variable?
I have the following class and the select clause is repeated can I store it as a variable somehow so I don't need to repeat it?
public class TractRepository : ITractRepository
{
private DataContext context;
public TractRepository(DataContext ctx) => context = ctx;
public async Task<IEnumerable<Tract>> GetAllAsync() =>
await context.Tracts.Include(p => p.ContractType).Include(p => p.ContractSubType).OrderByDescending(p => p.Id)
.Select(p => new Tract
{
Id = p.Id,
Acreage = p.Acreage,
Administrative = p.Administrative,
ContractType = new ContractType
{
Id = p.ContractType.Id,
ContractTypeName = p.ContractType.ContractTypeName
},
ContractSubType = new ContractSubType
{
Id = p.ContractSubType.Id,
ContractSubTypeName = p.ContractSubType.ContractSubTypeName
}
})
.ToListAsync();
public async Task<Tract> GetByIdAsync(long id) =>
await context.Tracts.Include(p => p.ContractType).Include(p => p.ContractSubType)
.Select(p => new Tract
{
Id = p.Id,
Acreage = p.Acreage,
Administrative = p.Administrative,
ContractType = new ContractType
{
Id = p.ContractType.Id,
ContractTypeName = p.ContractType.ContractTypeName
},
ContractSubType = new ContractSubType
{
Id = p.ContractSubType.Id,
ContractSubTypeName = p.ContractSubType.ContractSubTypeName
}
}).FirstOrDefaultAsync(p => p.Id == id);
}
You can extract the whole common IQueryable<T> to separate property/method. Since LINQ queries are not executed until enumerated (the so called deferred execution), it can be used as base for composing other queries, e.g.
private IQueryable<Tract> Query() => context.Tracts
//.Include(p => p.ContractType)
//.Include(p => p.ContractSubType)
.Select(p => new Tract
{
Id = p.Id,
Acreage = p.Acreage,
Administrative = p.Administrative,
ContractType = new ContractType
{
Id = p.ContractType.Id,
ContractTypeName = p.ContractType.ContractTypeName
},
ContractSubType = new ContractSubType
{
Id = p.ContractSubType.Id,
ContractSubTypeName = p.ContractSubType.ContractSubTypeName
}
});
(Includes are redundant (ignored) for projection (Select) queries)
then
public async Task<IEnumerable<Tract>> GetAllAsync() =>
await Query().OrderByDescending(p => p.Id).ToListAsync();
and
public async Task<Tract> GetByIdAsync(long id) =>
await Query().FirstOrDefaultAsync(p => p.Id == id);
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);
}
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>>();