I use UnitOfWork with repository in an ASP.NET Core 6 Web API and want to use XUnit for testing. I use the code shown below, and it works.
I have two questions:
I use accept-language in the methods to know what is the language for returning correct error messages. How can I add accept-language for test?
How should I use token that I get with Authenticate method?
UnitOfWork
public interface IUnitOfWork : IDisposable
{
IUserRepository UserRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
protected readonly DatabaseContext db;
private IUserRepository userRepository;
public IUserRepository UserRepository
{
get
{
if (userRepository == null)
{
userRepository = new UserRepository(db);
}
return userRepository;
}
}
//...
}
UserRepository
public interface IUserRepository : IGenericRepository<UserRole>
{
Task<User> GetUserWithRolesAsync(string username);
}
public class UserRepository : GenericRepository<User>, IUserRepository
{
public async Task<User> GetUserWithRolesAsync(string username)
{
//...
}
}
AuthController
private readonly IUnitOfWork _uow;
public AuthController(IUnitOfWork uow) : base(uow)
{
_uow = uow;
}
[HttpPost("authenticate")]
public async Task<IActionResult> Authenticate([FromBody] UserLoginViewModel Request)
{
User user = await _uow.UserRepository.GetUserWithRolesAsync(Request.Username);
//....
}
Test method:
[Fact]
public async Task Authenticate_WithInvalidUsernamePassword_ReturnsNotFound()
{
// Arrange
var dbOption = new DbContextOptionsBuilder<DatabaseContext>().UseSqlServer("connection string").Options;
DatabaseContext databaseContext = new DatabaseContext(dbOption);
databaseContext.Database.EnsureCreated();
var jwtAuthenticatorManager = new JwtAuthenticatorManager("key");
var unitOfWorkStub = new Mock<IUnitOfWork>();
UserRepository userRep = new UserRepository(databaseContext);
unitOfWorkStub.SetupGet(uow => uow.UserRepository).Returns(userRep);
var options = Options.Create(new LocalizationOptions { ResourcesPath = "Resources" });
var factory = new ResourceManagerStringLocalizerFactory(options, NullLoggerFactory.Instance);
var localizer = new StringLocalizer<SharedTranslate>(factory);
var controller = new AuthController(unitOfWorkStub.Object, localizer, jwtAuthenticatorManager);
UserLoginViewModel userLoginViewModel = new UserLoginViewModel
{
Username = "admin",
Password = "admin#123"
};
// Act
var result = await controller.Authenticate(userLoginViewModel);
// Assert
result.Should().BeOfType<NotFoundResult>();
}
Related
I am trying to implement dependency injection using entity framework but it is giving an exception of "An unhandled exception of type 'System.StackOverflowException' occurred in Unity.Container.dll" and application is gone on break mode
public class CategoryRepository : ICategoryRepository
{
private LaundryManagementSystemEntities context;
private ICategoryRepository _iCategory;
//public CategoryRepository(LaundryManagementSystemEntities db) //For repositoty Patterns or Unit of work
//{
// this.context = db;
//}
//For dependency Injection
public CategoryRepository(ICategoryRepository iCategory,LaundryManagementSystemEntities _context)
{
this._iCategory = iCategory;
this.context = _context;
}
public void CreateCategory(CategoryViewModel categoryViewModel)
{
var category = new Category();
category.CategoryName = categoryViewModel.CategoryName;
category.IsActive = categoryViewModel.IsActive;
context.Categories.Add(category);
context.SaveChanges();
}
Here is making Repository class of category
public interface ICategoryRepository:IDisposable
{
List<Category> GetCategories();
Category GetCategoryById(int? categoryId);
void CreateCategory(CategoryViewModel category);
void DeleteProductOfCategory(int productId);
void DeleteCategory(int categoryId);
void PostEditCategory(CategoryViewModel category);
CategoryViewModel GetEditCategory(int? categoryId);
}
This is an interface
public class CategoryController : AdminBaseController
{
LaundryManagementSystemEntities db = new LaundryManagementSystemEntities();
private ICategoryRepository interfaceobj;
//private UnitOfWork unitOfWork;
public CategoryController(ICategoryRepository iCategory)
{
this.interfaceobj = iCategory;
//For Repositorypatterns
//this.interfaceobj = new CategoryRepository(new LaundryManagementSystemEntities());
//For Unit Of Work
// this.unitOfWork = new UnitOfWork(new LaundryManagementSystemEntities());
}
// GET: Category
public ActionResult Index()
{
return View();
}
public ActionResult Create()
{
CategoryViewModel categoryViewModel = new CategoryViewModel();
return PartialView("Create",categoryViewModel);
}
[HttpPost]
public ActionResult Create(CategoryViewModel category)
{
if (ModelState.IsValid)
{
interfaceobj.CreateCategory(category);
// unitOfWork.CategoryRepository.CreateCategory(catogery);
// interfaceobj.CreateCategory(catogery);
}
return PartialView("Create",category);
}
This is the controller
I am not getting the exception
I want to know about it properly and how it would run
The injection of ICategoryRepository into CategoryRepository which is derived from the same interface is creating a cyclic/circular dependency which is causing the stack to overflow.
Remove that dependency. The code originally shown does not appear to use nor need that dependency.
public class CategoryRepository : ICategoryRepository {
private readonly LaundryManagementSystemEntities context;
public CategoryRepository(LaundryManagementSystemEntities context) {
this.context = context;
}
//...
I have implemented a unit test on my ASP.NET Core MVC project using xUnit. When I try to run the test, it gave me an error as below:
The following constructor parameters did not have matching fixture data: Status status"
Below is my code:
IStatusService:
public interface IStatusService
{
Task<StatusIndexViewModel> GetStatusAsync();
}
StatusService:
public class StatusService : IStatusService
{
private readonly DbContext dbContext;
private readonly IMapper mapper;
public StatusService(DbContext dbContext, IMapper mapper)
{
this.dbContext = dbContext;
this.mapper = mapper;
}
public async Task<StatusIndexViewModel> GetStatusAsync()
{
var model = await dbContext
.Status.AsNoTracking()
.ProjectTo<StatusViewModel>(mapper.ConfigurationProvider)
.ToListAsync();
var vm = new StatusIndexViewModel
{
Statuses = model
};
return vm;
}
}
Here is the Controller:
public class StatusController : Controller
{
private readonly IStatusService statusService;
public StatusController(IStatusService statusService)
{
this.statusService = statusService;
}
public async Task<IActionResult> Index()
{
var model = await statusService.GetStatusAsync();
return View(model);
}
}
Below is my unit test class:
public class StatusUnitTest
{
StatusController StatusControllerTest;
private Mock<IStatusService> statusService;
private List<Status> statuses;
private Status status;
public StatusUnitTest(Status status)
{
this.status = status;
statusService = new Mock<IStatusService>();
statusService.Setup(p =>
p.GetStatusAsync()).ReturnsAsync(status);
StatusControllerTest = new StatusController(statusService.Object);
}
[Fact]
public async Task GetStatusByIdNo()
{
var result = await StatusControllerTest.Index();
var viewResult = Assert.IsType<ViewResult>(result);
Assert.IsAssignableFrom<IEnumerable<Status>>
(viewResult.ViewData.Model);
}
}
May I know what mistake I made? How I can test the controller and the service layer? Please give me a guide.
I have dot net core website , based on dependency injection ,the controller is.
public class TokenController : Controller
{
private IConfiguration _config;
private readonly IUserService _iuserService;
public TokenController(IConfiguration config, IUserService iUserService)
{
_config = config;
_iuserService = iUserService;
}
public UserViewModel Authenticate(LoginModel login)
{
UserViewModel user = null;
user = this._iuserService.Login(login.Username, login.Password);
return user;
}
}
and i want to do unit test for Authenticate method ,the unit test class is ,
[TestClass]
public class TokenUnitTest
{
private IUserService _IUserService;
private IConfiguration _config;
[TestInitialize]
public void Setup()
{
var mockIUserService = new Mock<IUserService>();
UserViewModel returnedobj = new UserViewModel();
returnedobj.Email = "sam#sam.com";
returnedobj.Name = "sam";
mockIUserService.Setup(x => x.Login("sam", "123")).Returns(returnedobj);
_IUserService = mockIUserService.Object;
var _configurationRoot = new Mock<IConfigurationRoot>();
_configurationRoot.SetupGet(x => x[It.IsAny<string>()]).Returns("Key");
this._config = _configurationRoot.Object;
}
[TestMethod]
public void Authenticate()
{
////arrange
LoginModel _LoginModel = new LoginModel("sam", "123");
var config = InitConfiguration();
var clientId = config["CLIENT_ID"];
TokenController _TokenController = new TokenController(config, _IUserService);
////act
UserViewModel LoginnedUser = _TokenController.Authenticate(_LoginModel);
////assert
Assert.IsNotNull(LoginnedUser);
}
}
The problem is when i put break point at authenticate method it return the returnd data that exist in setupMock. Why it doesn't go to database and return the true data.
the second problem is the breakpoint doesn't enter in UserService ,it deal with interface ,, why dependency injection doesn't work ??
For an integration test no mocking is required:
[TestInitialize]
public void Setup()
{
_IUserService = new UserService(); // create a real instance
}
I'm trying to test my project. I have never used tests before and I am starting to learn I would like a help, in the simplest case I want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Controller:
Controller:
public class WorkPlacesController : Controller
{
private readonly IWorkPlaceService workPlaceService;
public WorkPlacesController(IWorkPlaceService workPlaceService)
{
this.workPlaceService = workPlaceService;
}
// GET: WorkPlaces
public ActionResult Index()
{
var workPlaces = workPlaceService.GetWorkPlaces(includedRelated:
true);
return View(workPlaces);
}
}
Here is my Service
Service
public class WorkPlaceService : IWorkPlaceService
{
private readonly IWorkPlaceRepository workPlacesRepository;
private readonly IUnitOfWork unitOfWork;
public WorkPlaceService(IWorkPlaceRepository workPlacesRepository, IUnitOfWork unitOfWork)
{
this.workPlacesRepository = workPlacesRepository;
this.unitOfWork = unitOfWork;
}
}
public interface IWorkPlaceService
{
IEnumerable<WorkPlace> GetWorkPlaces(string workPlaceDescription = null, bool includedRelated = true);
}
And my Repository
Repository
public class WorkPlaceRepository : RepositoryBase<WorkPlace>, IWorkPlaceRepository
{
public WorkPlaceRepository(IDbFactory dbFactory)
: base(dbFactory) { }
public WorkPlace GetWorkPlaceByDescription(string workPlaceDescription)
{
var workPlace = this.DbContext.WorkPlaces.Where(c => c.Description == workPlaceDescription).FirstOrDefault();
return workPlace;
}
}
public interface IWorkPlaceRepository : IRepository<WorkPlace>
{
WorkPlace GetWorkPlaceByDescription(string workPlaceDescription);
}
Factory
public class DbFactory : Disposable, IDbFactory
{
AgendaEntities dbContext;
public AgendaEntities Init()
{
return dbContext ?? (dbContext = new AgendaEntities());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
I tried to do something like this:
public void BasicIndexTest()
{
// Arrange
var mockRepository = new Mock<IWorkPlaceService>();
var controller = new WorkPlacesController(mockRepository.Object);
// Act
ActionResult actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsInstanceOfType(actionResult, typeof(List<WorkPlace>));
}
How do I inject in this controller the data needed to go in the database and bring the results?
I Want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Mock the behavior of required dependencies of the controller for the test and assert the desired behavior when the test is exercised.
For example, based on what you have done so far
public void BasicIndexTest() {
// Arrange
var mockService = new Mock<IWorkPlaceService>();
var workPlaces = new List<WorkPlace>() {
new WorkPlace()
};
mockService
.Setup(_ => _.GetWorkPlaces(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(workPlaces);
var controller = new WorkPlacesController(mockService.Object);
// Act
var actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(actionResult);
var model = actionResult.Model;
Assert.IsNotNull(model)
Assert.IsInstanceOfType(model, typeof(List<WorkPlace>));
Assert.AreEqual(workPlaces, model);
}
Only the IWorkPlaceService was needed for the testing of Index action, but fake data was needed for the invocation of the GetWorkPlaces method. So the mock was configured to return a list of objects when called and pass it to the view result.
How can I test ClassifyComment() method from my service. I have that test code:
[TestClass]
public class SpamServiceTest
{
[TestMethod]
public void ClassifyCommentTest()
{
var spamComments = Builder<Comments>.CreateListOfSize(10).All().With(x => x.Content = "spam spam spam")
.Build().AsQueryable();
var mocker = new AutoMoqer();
mocker.GetMock<IUnitOfWork>()
.Setup(x => x.CommentsRepository.GetComments(It.Is<bool>(y => y == true)))
.Returns(spamComments);
//.......
}
}
But it gives me error: Can not instantiate proxy of class: CommentsRepository. Could not find a parameterless constructor.
Below is my code which I want test:
public class SpamService : ISpamService
{
private readonly IUnitOfWork _unitOfWork;
public SpamService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public bool ClassifyComment(Comments comment)
{
var spam = _unitOfWork.CommentsRepository.GetComments(true).ToList();
//.............
}
}
public class UnitOfWork : IUnitOfWork
{
private DatabaseContext context = new DatabaseContext();
private CommentsRepository commentsRepository;
public CommentsRepository CommentsRepository
{
get
{
if (this.commentsRepository == null)
{
this.commentsRepository = new CommentsRepository(context);
}
return commentsRepository;
}
}
}
public class CommentsRepository : ICommentsRepository
{
private DatabaseContext context;
public CommentsRepository(DatabaseContext context)
{
this.context = context;
}
public virtual IQueryable<Comments> GetComments(bool isSpam)
{
//.......
}
}
IUnityOfWork should return a ICommentsRepository, i.e. an interface, not an implementation. The mock of IUnityOfWork should return a mock of ICommentsRepository.
Let the abstraction work with other abstractions, not with implementations.