Using Unit, I'm trying to setup a test where I can delete an entry from my Mock list in order to test out the implementation in my CustomerManager.
My Repository:
public class Repository<T> : IRepository<T> where T : ModelBase
{
private readonly CustomerDbContext _context;
public Repository(CustomerDbContext context)
{
if (_context == null)
throw new ArgumentNullException(nameof(context));
_context = context;
}
public async Task Delete(int id, bool softDelete = true)
{
var entity = await GetById(id);
if (entity == null) return;
if (softDelete)
{
entity.IsDeleted = true;
Save(entity);
}
else
_context.Set<T>().Remove(entity);
}
public async Task<T> GetById(int id)
{
return await _context.Set<T>().FirstOrDefaultAsync(t => t.Id == id).ConfigureAwait(false);
}
public void Save(T entity)
{
if (entity.Id == 0)
_context.Set<T>().Add(entity);
else
_context.Entry(entity).State = EntityState.Modified;
}
}
My Unit Of Work is:
public class CustomerUnitOfWork : IUnitOfWork
{
public CustomerDbContext Context { get; }
public async Task<int> Commit()
{
foreach(var item in Context.ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
{
if (!(item.Entity is ModelBase entity))
continue;
if (item.State == EntityState.Added)
{
entity.CreatedDate = DateTime.UtcNow;
}
entity.ModifiedDate = DateTime.UtcNow;
}
return await Context.SaveChangesAsync();
}
}
My Manager is:
public class CustomerManager : ICustomerManager
{
private readonly IRepository<Models.Customer> _customerRepository;
protected readonly IUnitOfWork _unitOfWork;
public CustomerManager(IRepository<Models.Customer> customerRepository, IUnitOfWork unitOfWork)
{
_customerRepository = customerRepository;
_unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
}
public async Task<int> Delete(int id, bool softDelete = true)
{
await _customerRepository.Delete(id, softDelete);
return await _unitOfWork.Commit();
}
public async Task<Models.Customer> GetById(int id)
{
return await _customerRepository.GetById(id);
}
}
In my Unit Test, I'm setting up the constructor like this:
private ICustomerManager MockManager;
private Mock<IUnitOfWork> UnitOfWork;
private List<Models.Customer> Customers;
Mock<IRepository<Models.Customer>> MockRepository;
public CustomerTest()
{
MockRepository = new Mock<IRepository<Models.Customer>>();
UnitOfWork = new Mock<IUnitOfWork>();
Customers = new List<Models.Customer>()
{
new Models.Customer
{
Id = 1,
Name = "Foo",
City = "Baltimore",
Company = "Foo Company"
},
new Models.Customer
{
Id = 2,
Name = "Bar",
City = "Owings Mills",
Company = "Bar Company"
}
};
MockRepository.Setup(repo => repo.GetAll()).ReturnsAsync(Customers);
MockRepository.Setup(repo => repo.GetById(It.IsAny<int>())).ReturnsAsync((int i) => Customers.SingleOrDefault(c => c.Id == i));
MockRepository.SetupAllProperties();
MockManager = new CustomerManager(MockRepository.Object, UnitOfWork.Object);
}
In my test method, I want to remove the first object in my test list.
public async Task ShouldDelete()
{
var countBeforeDelete = Customers.Count();
var countAfterDelete = await MockManager.Delete(1, true);
Assert.Equal(countBeforeDelete, countAfterDelete);
}
However, CountAfterDelete always returns 0. I'm not sure what I'm doing wrong.
Your Manager's Delete method returns await _unitOfWork.Commit();
By default, the Mock of IUnitOfWork will return default(int) which is 0.
Related
I have a Category table in my project, I used Generic repository and Unit of Work pattern in my project. It is an API. It is working when I use mock of UnitOfWork lonely but It is not working when I want to check my controller result. My controller response is 404 always. I think it is because of my mistake in setup but I don't know where it is.
`
[DisplayName("Category Table")]
public class Category
{
public int Id { get; set; }
public int? Priority { get; set; }
public string Name { get; set; }
public string? Details { get; set; }
public bool Enabled { get; set; }
public int? ParentCategoryId { get; set; }
public virtual Category Parent { get; set; }
public virtual IList<Category> Children { get; set; }
}
public interface IGenericRepository<T> where T : class, new()
{
Task<T> GetByIdAsync(object id);
Task<IReadOnlyList<T>> ListAllAsync();
Task<T> GetEntityWithSpec(ISpecification<T> spec);
Task<IReadOnlyList<T>> ListWithSpecAsync(ISpecification<T> spec);
...
}
public class GenericRepository<T> : IGenericRepository<T> where T : class, new()
{
private readonly FactoryContext _context;
public GenericRepository(FactoryContext context)
{
_context = context;
}
public async Task<T> GetByIdAsync(object id)
{
return await _context.Set<T>().FindAsync(id);
}
public async Task<IReadOnlyList<T>> ListAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public async Task<T> GetEntityWithSpec(ISpecification<T> spec)
{
return await ApplySpecification(spec).FirstOrDefaultAsync();
}
public async Task<IReadOnlyList<T>> ListWithSpecAsync(ISpecification<T> spec)
{
return await ApplySpecification(spec).ToListAsync();
}
...
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
}
}
public interface IUnitOfWork : IDisposable
{
IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class, new();
Task<int> Complete();
}
public class UnitOfWork : IUnitOfWork
{
private readonly FactoryContext _context;
private Hashtable _repositories;
public UnitOfWork(FactoryContext context)
{
_context = context;
}
public async Task<int> Complete()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
public IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class, new()
{
if (_repositories == null) _repositories = new Hashtable();
var type = typeof(TEntity).Name;
if (!_repositories.ContainsKey(type))
{
var repositoryType = typeof(GenericRepository<>);
var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _context);
_repositories.Add(type, repositoryInstance);
}
return (IGenericRepository<TEntity>)_repositories[type];
}
}
public class CategoriesController : BaseApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public CategoriesController(IUnitOfWork unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
[HttpGet("getcategorybyid/{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status400BadRequest)]
public async Task<ActionResult<CategoryToReturnDto>> GetCategoryById(int id)
{
try
{
var spec = new GetCategoriesWithParentsSpecification(id);
var category = await _unitOfWork.Repository<Category>().GetEntityWithSpec(spec);
if (category.Id == 0) return NotFound(new ApiResponse(404));
var returnCategories = _mapper.Map<Category, CategoryToReturnDto>(category);
return new OkObjectResult(new ApiResponse(200, "Ok", returnCategories));
}
catch (Exception ex)
{
return BadRequest(new ApiResponse(400, ex.Message));
}
}
}
public class CategoriesControllerTests
{
private readonly Mock<IMapper> _mapper;
private readonly Mock<IUnitOfWork> _unitOfWork;
public CategoriesControllerTests()
{
_mapper = new Mock<IMapper>();
_unitOfWork = new Mock<IUnitOfWork>();
}
[Fact]
public async Task Get_OK_ObjectResult_CategoryById()
{
//Arrange
Category newCategory = CreateTestCategory();
var spec = new GetCategoriesWithParentsSpecification(1);
_unitOfWork.Setup(x => x.Repository<Category>().GetEntityWithSpec(spec)).ReturnsAsync(newCategory)
.Verifiable();
//Act
// Here it is working and result2 has data.
var result2 = await _unitOfWork.Object.Repository<Category>().GetEntityWithSpec(spec);
var controller = new CategoriesController(_unitOfWork.Object, _mapper.Object);
var result = await controller.GetCategoryById(1);
// Assert
result.Value?.Id.ShouldBe(newCategory.Id);
result.Value?.Name.ShouldBeEquivalentTo(newCategory.Name);
result.Value?.Name.ShouldBeEquivalentTo("newCategory.Name");
// My problem here. My result is NotFoundObjectResult always.
result.Result.ShouldBeOfType<OkObjectResult>();
}
private Category CreateTestCategory()
{
return new Category()
{
Id = 1,
Priority = 1,
Name = "Test Category",
Enabled = true,
Details = "Testing category data"
};
}
}
`
The spec that you pass during the moq setup isn't the same as the spec that your repository receives inside the controller
In your test, you should change the setup in such a way that it checks the type of input instead and avoid passing a reference.
_unitOfWork.Setup(x => x.Repository<Category>()
.GetEntityWithSpec(It.IsAny<ISpecification<Category>>()))
.ReturnsAsync(newCategory)
.Verifiable();
Here we set up the moq in a way that as long as the input is ISpecification<Category>, it returns newCategory
The specificatio didn't use truly. Your setup should be like this:
_unitOfWork.Setup(x => x.Repository<Category>()
.GetEntityWithSpec(It.IsAny<ISpecification<Category>>()))
.ReturnsAsync(newCategory)
.Verifiable();
I am trying to apply patch operation in Data Layer Repository but due to have no Model State available in Data Layer i am unable to update it. I have debug the overall logic i come to the conclusion that patch.ApplyTo() operation update the Model but context.SaveChanges() is not updating the database context.
Below is the context class
public class ApplicationDbContext : DbContext, IApplicationDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> opts) : base(opts)
{
}
public override int SaveChanges()
{
return base.SaveChanges();
}
}
Below is the repositroy method code
public class SpotWriteOnly : ISpotWriteOnly {
private IApplicationDbContext _context;
public SpotWriteOnly(IApplicationDbContext context)
{
_context = context;
}
public int UpdateSpot(long id, JsonPatchDocument<SpotData> patch) {
Spot s = _context.Spots.Include(x => x.Agent)
.Include(x => x.Channel)
.Include(x => x.Timeband)
.Include(x => x.Region)
.Include(x => x.Sponsor)
.Include(x => x.SpotType)
.Include(x => x.Status)
.Include(x => x.SpotStatusReason)
.OrderByDescending(x => x.Version)
.FirstOrDefault(x => x.SpotId == id && x.IsDeleted == false);
SpotData sData = new SpotData { Spot = s };
patch.ApplyTo(sData);
int response = _context.SaveChanges();
return response;
}
}
Below is the Handler Class
public class UpdateSpotQueryHandler : IRequestHandler<UpdateSpotQuery, int> {
public ISpotWriteOnly _repository;
public IMapper _mapper;
public UpdateSpotQueryHandler(ISpotWriteOnly repository, IMapper mapper)
{
_repository = repository;
_mapper = mapper;
}
public Task<int> Handle(UpdateSpotQuery query, CancellationToken cancellationToken) {
return Task.FromResult(_repository.UpdateSpot(query.SpotId, query.Patch));
}
}
Below is the Query
public class UpdateSpotQuery : IRequest<int> {
public long SpotId { get; set; }
public JsonPatchDocument<SpotData> Patch { get; set; }
}
Below is the controller code
[HttpPatch("{id}")]
public IActionResult UpdateSpot(long id,[FromBody] JsonPatchDocument<SpotData> patch) {
if(ModelState.IsValid) {
var result = Mediator.Send(new UpdateSpotQuery { SpotId = id, Patch = patch} );
var response = new Envelop
{
IsSuccessful = true,
StatusCode = 200,
StatusMessage = "OK",
Response = result.Result,
isExceptionGenerated = false,
Exception = null,
};
return Ok(response);
}
else {
var response = new Envelop
{
IsSuccessful = false,
StatusCode = 200,
StatusMessage = "Error in Model",
Response = ModelState,
isExceptionGenerated = true,
Exception = new Exception[] { new ArgumentException()},
};
return BadRequest(response);
}
}
I am trying to update database using patch operation in data layer.
Test class:
public class PlantDataControllerTests
{
private Mock<PlantDataService> serviceStub = new Mock<PlantDataService>();
private Mock<ILogger<PlantDataController>> loggerStub = new Mock<ILogger<PlantDataController>>();
private PlantDataController controller;
public PlantDataControllerTests()
{
serviceStub = new Mock<PlantDataService>(MockBehavior.Strict);
serviceStub.Setup(service => service.GetItemAsync(It.IsAny<string>()))
.ReturnsAsync((PlantData)null);
loggerStub = new Mock<ILogger<PlantDataController>>();
controller = new PlantDataController(serviceStub.Object, loggerStub.Object);
}
[Fact]
public async Task GetItemAsync_WithExisitingItem_ReturnsExpectedItem()
{
var expectedItem = CreateRandomPlantData();
serviceStub.Setup(service => service.GetItemAsync(It.IsAny<string>()))
.ReturnsAsync(expectedItem);
var result = await controller.GetItemAsync(expectedItem.Id);
result.Value.Should().BeEquivalentTo(expectedItem, opt => opt.ComparingByMembers<PlantData>());
}
[Fact]
public async Task GetItemAsync_WithExisitingItemByTopic_ReturnsExpectedItem()
{
//Arrange
var expectedItems = new[] { CreateRandomPlantData(), CreateRandomPlantData(), CreateRandomPlantData() };
serviceStub.Setup(s => s.GetItemsFromTopicAsync(It.IsAny<string>())).ReturnsAsync(expectedItems.ToList());
//Act
var actualItems = await controller.GetItemsFromTopicAsync("plant/soilHumidity/2");
//Assert
actualItems.Should().BeEquivalentTo(expectedItems, opt => opt.ComparingByMembers<PlantData>());
}
[Fact]
public async Task GetItemsAsync_WithExisitingItems_ReturnsAllItems()
{
var expectedItems = new[] {CreateRandomPlantData(), CreateRandomPlantData(), CreateRandomPlantData()};
serviceStub.Setup(s => s.GetItemsAsync()).ReturnsAsync(expectedItems.ToList());
var actualItems = await controller.GetItemsAsync();
actualItems.Should().BeEquivalentTo(expectedItems, opt => opt.ComparingByMembers<PlantData>());
}
private PlantData CreateRandomPlantData()
{
return new()
{
Id = "60ae78fd9afed8cbe0b30336",
TimeStamp = DateTime.Now,
Topic = "plant/soilHumidity/2",
Value = new Random().Next(0, 3000)
};
}
}
Controller:
[Route("api/[controller]")]
[EnableCors("MyPolicy")]
[ApiController]
public class PlantDataController : ControllerBase
{
private readonly PlantDataService plantDataService;
private readonly ILogger<PlantDataController> logger;
public PlantDataController(PlantDataService plantDataService, ILogger<PlantDataController> logger)
{
this.plantDataService = plantDataService;
this.logger = logger;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<PlantDataDto>>> GetItemsAsync()
{
var plantData = (await plantDataService.GetItemsAsync()).Select(p => p.AsDto());
var plantDataDtos = plantData.ToList();
logger.LogInformation($"{DateTime.Now.ToString("HH:mm:ss")}: Retrieved {plantDataDtos.ToList()}");
return Ok(plantDataDtos);
}
[HttpGet("{topic}", Name = "GetPlantDataFromTopic")]
public async Task<ActionResult<IEnumerable<PlantDataDto>>> GetItemsFromTopicAsync(string topic)
{
if(string.IsNullOrEmpty(topic))
return NotFound();
var plantData = (await plantDataService.GetItemsFromTopicAsync(HttpUtility.UrlDecode(topic))).Select(p => p.AsDto());
var plantDataDtos = plantData.ToList();
logger.LogInformation($"{DateTime.Now.ToString("HH:mm:ss")}: Retrieved {plantDataDtos.ToList()}");
return Ok(plantDataDtos);
}
[HttpGet("{id:length(24)}", Name = "GetPlantData")]
public async Task<ActionResult<PlantDataDto>> GetItemAsync(string id)
{
if(string.IsNullOrEmpty(id))
return NotFound();
var plantData = await plantDataService.GetItemAsync(id);
if (plantData is null)
{
return NotFound();
}
logger.LogInformation($"{DateTime.Now.ToString("HH:mm:ss")}: Retrieved plantdata: {plantData.Id}");
return Ok(plantData.AsDto());
}
}
Service:
public class PlantDataService : IPlantDataService
{
private readonly IMongoCollection<PlantData> _plants;
public PlantDataService(IPlantStarterDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_plants = database.GetCollection<PlantData>(settings.PlantStarterCollectionName);
}
public PlantDataService()
{
}
public virtual async Task<List<PlantData>> GetItemsAsync() => await _plants.Find(plant => true).ToListAsync();
public virtual async Task<PlantData> GetItemAsync(string id) => await _plants.Find(p => p.Id == id).SingleOrDefaultAsync();
public virtual async Task<List<PlantData>> GetItemsFromTopicAsync(string topic) => await _plants.FindAsync(p => p.Topic == topic).Result.ToListAsync();
}
AsDto method:
public static class DtoExtensions
{
public static PlantDataDto AsDto(this PlantData plantdata)
{
return new()
{
Id = plantdata.Id,
TimeStamp = plantdata.TimeStamp,
Topic = plantdata.Topic,
Value = plantdata.Value
};
}
}
Every assert result returns null.
I do not really know what goes wrong here...
The test all went green until some point i changed the Value from int to double, but that seems very strange that is the cause of my unit tests failing because the calls itself just works in swagger and Postman.
I have a model called notes that I am feeding into a kendo grid via calls to an interface / repository class. Everything works but it is running synchronously and I want to run it asynchronously.
I'm using .NET core 3.1 so IAsyncEnumerable etc should all be available if I can work out how to do it. I've tried a lot of variations but always get errors. Any help much appreciated.
This is the interface
namespace FliveRetry.Models.PTs
{
public interface IPtNoteRepository
{
IEnumerable<Note> GetAllNotes();
Note GetNoteById(int NoteId);
}
}
This is the repository
namespace FliveRetry.Models.PTs
{
public class PtNoteRepository : IPtNoteRepository
{
private readonly FliveRetryContext context;
public PtNoteRepository(FliveRetryContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
}
public IEnumerable<Note> GetAllNotes()
{
return context.Note;
}
public Note GetNoteById(int itemId)
{
var note = context.Note.SingleOrDefault(i => i.ID == itemId);
return note;
}
}
}
and this is the index model where I'm calling it and feeding it to the grid via OnPostRead
namespace FliveRetry.Pages.Notes
{
public class IndexModel : NoteSelectPageModel
{
private const int CURRENT_USER_ID = 21; //Fake user id for demo
private readonly IPtNoteRepository rpsNotesRepo;
public static IList<Note> Notes { get; set; }
[BindProperty(SupportsGet = true)]
public NoteScreenEnum? PresetScreen { get; set; }
public IndexModel(IPtNoteRepository rpsNotesData)
{
rpsNotesRepo = rpsNotesData;
}
public void OnGet()
{
IEnumerable<Note> notes;
switch (PresetScreen)
{
case NoteScreenEnum.GeneralNotes:
notes = rpsNotesRepo.GetAllNotes();
break;
case NoteScreenEnum.ThisNote:
notes = rpsNotesRepo.GetNoteByID(CURRENT_USER_ID);
break;
default:
notes = rpsNotesRepo.GetAllNotes();
break;
}
Notes = notes.ToList();
}
public JsonResult OnPostRead([DataSourceRequest] DataSourceRequest request)
{
return new JsonResult(Notes.ToDataSourceResult(request));
}
}
}
In other pages like create or edit.cshtml.cs for example I am successfully using async to edit and create, e.g:
namespace FliveRetry.Pages.Notes
{
public class EditModel : NoteSelectPageModel
{
private readonly FliveRetry.Data.FliveRetryContext _context;
public EditModel(FliveRetry.Data.FliveRetryContext context)
{
_context = context;
}
[BindProperty]
public Note Note { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Note = await _context.Note
.AsNoTracking()
.FirstOrDefaultAsync(m => m.ID == id);
if (Note == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(IFormCollection form, int? id, string[] selectedOrgs, string[] selectedClients, string[] selectedStaffs, string[] selectedNoteTypes)
{
if (!ModelState.IsValid)
{
return Page();
}
var noteToUpdate = await _context.Note
.FirstOrDefaultAsync(s => s.ID == id);
if (await TryUpdateModelAsync<Note>(noteToUpdate, "note", // Prefix for form value.
c => c.Title, c => c.NoteText, c => c.NoteDate, c => c.Amount, c => c.ImageURL, c => c.FileURL, c => c.Archived, c => c.DateSaved, c => c.UserID, c => c.StartTime, c => c.FinishTime))
{
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
return Page();
}
}
}
Try to use below code to convert synchronous action to asynchronous action:
IPtNoteRepository:
public interface IPtNoteRepository
{
Task<IEnumerable<Note>> GetAllNotesAsync();
Task<Note> GetNoteByIdAsync(int NoteId);
}
Repository:
public class PtNoteRepository : IPtNoteRepository
{
private readonly FliveRetryContext context;
public PtNoteRepository(FliveRetryContext context)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
}
public async Task<IEnumerable<Note>> GetAllNotesAsync()
{
return await context.Note.ToListAsync();
}
public async Task<Note> GetNoteByIdAsync(int itemId)
{
var note = await context.Note.SingleOrDefaultAsync(i => i.ID == itemId);
return note;
}
}
IndexModel:
public async Task OnGetAsync()
{
IEnumerable<Note> notes;
switch (PresetScreen)
{
case NoteScreenEnum.GeneralNotes:
notes = await rpsNotesRepo.GetAllNotesAsync();
break;
case NoteScreenEnum.ThisNote:
notes = await rpsNotesRepo.GetNoteByIdAsync(CURRENT_USER_ID);
break;
default:
notes = await rpsNotesRepo.GetAllNotesAsync();
break;
}
Notes = notes.ToList();
}
I have a project. It is simple License Manager.
I have such DbContext (Entity Framework 5):
public class EFDbContext : DbContext
{
public virtual IDbSet<License> Licenses { get; set; }
public virtual IDbSet<Department> Departments { get; set; }
public virtual IDbSet<Its> Itses { get; set; }
}
I created an IUnitOfWork implementation:
public class UnitOfWork : IUnitOfWork
{
private readonly EFDbContext Db;
private readonly LicenseRepository LicenseRepository;
private readonly DepartmentRepository DepartmentRepository;
private readonly ItsRepository ItsRepository;
public UnitOfWork(EFDbContext context)
{
Db = context;
DepartmentRepository = DepartmentRepository ?? (DepartmentRepository = new DepartmentRepository(Db));
ItsRepository = ItsRepository ?? (ItsRepository = new ItsRepository(Db));
LicenseRepository = LicenseRepository ?? (LicenseRepository = new LicenseRepository(Db));
}
public IRepository<License> Licenses
{
get { return LicenseRepository; }
}
public IRepository<Department> Departments
{
get { return DepartmentRepository; }
}
public IRepository<Its> Itses
{
get { return ItsRepository; }
}
}
And I have an IRepository implementation named LicenseRepository:
public class LicenseRepository : IRepository<License>
{
private EFDbContext Db;
public LicenseRepository(EFDbContext context)
{
Db = context;
}
public IQueryable<License> Items
{
get { return Db.Licenses.Include(lic => lic.Department).Include(lic => lic.Its); }
}
private bool CheckIfExist(string codeAct, int id)
{
return (id == 0)
? Db.Licenses.Any(license => license.CodeAct.Equals(codeAct))
: Db.Licenses.Any(license => license.CodeAct.Equals(codeAct) && license.Id != id);
}
private void Defend(License item)
{
Security sec = Security.Instance;
Its its = Db.Itses.FirstOrDefault(i => i.Id == item.ItsId);
item.CodeLic = item.CodeLic.ToUpper()/*.Replace("-", " - ")*/;
string hash = sec.GetHash(item.CodeLic.Replace(" - ", ""), (its == null) ? string.Empty : its.Salt);
item.CodeAct = hash.Insert(5," - ");
}
public IQueryable<License> GetOrderBy<TResult>(string order, IQueryable<License> items, Expression<Func<License, TResult>> key)
{
return (order == null || order.ToUpper() == "ASC") ? items.OrderBy(key) : items.OrderByDescending(key);
}
public void Edit(License item)
{
Defend(item);
if (CheckIfExist(item.CodeAct, item.Id)) throw new DbUpdateException("Error update");
if (item.Id == 0)
{
Db.Licenses.Add(item);
}
else
{
License dbEntry = Db.Licenses.Find(item.Id);
if (dbEntry != null)
{
dbEntry.CodeLic = item.CodeLic;
dbEntry.CodeAct = item.CodeAct;
dbEntry.Peom = item.Peom;
dbEntry.Phone = item.Phone;
dbEntry.Pib = item.Pib;
dbEntry.DepartmentId = item.DepartmentId;
dbEntry.ItsId = item.ItsId;
dbEntry.Dtime = item.Dtime;
}
}
Db.SaveChanges();
}
public License Delete(int id)
{
License dbEntry = Db.Licenses.Find(id);
if (dbEntry != null)
{
Db.Licenses.Remove(dbEntry);
Db.SaveChanges();
}
return dbEntry;
}
}
My LicenseController looks like:
public class LicenseController: Controller
{
private IUnitOfWork Repository;
public LicenseController(IUnitOfWork _repository)
{
Repository = _repository;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(LicenseViewModel model)
{
if (ModelState.IsValid) // валидация данных
{
model.License.DepartmentId = model.License.DepartmentId == 0 ? null : model.License.DepartmentId;
model.License.ItsId = model.License.ItsId == 0 ? null : model.License.ItsId;
if (model.License.Dtime == DateTime.MinValue)
{
model.License.Dtime = DateTime.Now;
}
model.License.CodeLic = string.Join(" - ", model.CodePart1, model.CodePart2, model.CodePart3,
model.CodePart4);
Repository.Licenses.Edit(model.License);
// хранится, пока мы их не прочитаем (ViewBag(не может хранить дольше текущего запроса) и Session(требует явного удаления) нам не подходят)
TempData["message"] = string.Format("Об'єкт \"{0}\" збережений", model.License.CodeLic);
return RedirectToAction("List");
}
// в случае неудачи
model.DropDownDepartment = GetDepartments(model.License.DepartmentId);
model.DropDownIts = GetItses(model.License.ItsId);
return View(model);
}
// another methods ...
}
I want to test if Edit method of Repository calls correctly when I pass correct Entity to it. My Mock class looks like:
private IDbSet<T> GetQueryableMockDbSet<T>(IQueryable<T> sourceList) where T: class
{
Mock<IDbSet<T>> mockSet = new Mock<IDbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(t => t.Provider).Returns(sourceList.Provider);
mockSet.As<IQueryable<T>>().Setup(t => t.Expression).Returns(sourceList.Expression);
mockSet.As<IQueryable<T>>().Setup(t => t.ElementType).Returns(sourceList.ElementType);
mockSet.As<IQueryable<T>>().Setup(t => t.GetEnumerator()).Returns(sourceList.GetEnumerator());
return mockSet.Object;
}
[TestMethod]
public void CanSaveValidLicense()
{
// ARRANGE
// создали пустое имитированное хранилище
var mockContext = new Mock<EFDbContext>();
IUnitOfWork iuow = GetFakeRepository();
mockContext.Setup(context => context.Itses).Returns(GetQueryableMockDbSet(iuow.Itses.Items));
mockContext.Setup(context => context.Departments).Returns(GetQueryableMockDbSet(iuow.Departments.Items));
mockContext.Setup(context => context.Licenses).Returns(GetQueryableMockDbSet(iuow.Licenses.Items));
var mockRepo = new Mock<UnitOfWork>(mockContext.Object);
mockRepo.CallBase = true;
// создаем контроллер
LicenseController target = new LicenseController(mockRepo.Object);
// создаем объект типа License
LicenseViewModel lvm = new LicenseViewModel
{
License = new License
{
CodeAct = "ABCD",
CodeLic = "DCBA",
Peom = "111",
Phone = "777",
Pib = "BDV",
DepartmentId = 1,
ItsId = 1
}
};
// ACT
// пытаемся сохранить новосозданный объект
ActionResult result = target.Edit(lvm);
// ASSERT
// проверяем, что был вызван метод хранилища на сохранение
//mockContext.Verify(context => context.SaveChanges());
//licRep.Verify(repository => repository.Edit(lvm.License), Times.Once());
mockRepo.As<IRepository<License>>().Verify(work => work.Edit(lvm.License), Times.Once());
mockRepo.VerifyAll();
// проверяем, что сохранение прошло успешно - произошло перенаправление на страницу (не остались на текущей)
Assert.IsNotInstanceOfType(result, typeof (ViewResult));
}
I have a headache with Verify method. It throws NotSupportedException or if I try another way it throws another Exception. I'm new in unit-testing. So, can you please help me with this problem.