I am using ASP.Net Core 3.1 Repository Pattern and Unit of Work Using Dapper .
I have use mediator as
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace TaskManagementApp.Api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ApiController : ControllerBase
{
private IMediator _mediator;
protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();
}
}
i am facing issue how can i write unit test to set value for HttpContext.RequestServices.GetService
here is my controller to be unit tested
namespace OneCubeCoaching.API.WebApi.Controllers
{
[Route("api/[controller]")]
public class ContactController : BaseApiController
{
[Authorize]
[HttpGet("GetAll")]
public async Task<IActionResult> Index()
{
return Ok(await Mediator.Send(new GetAllClientQuery()));
}
}
}
Just depend on IMediator in the constructor.
Assuming your code you meant ApiController was in fact BaseApiController (per your second code segment) something like this will work:
[Route("api/[controller]")]
[ApiController]
public class BaseApiController : ControllerBase
{
protected ApiController(IMediator mediator)
{
_mediator = mediator;
}
protected IMediator {get; private set;}
}
Then your ContactController can pass IMediator to base:
[Route("api/[controller]")]
public class ContactController : BaseApiController
{
public ContactController (IMediator mediator)
:base(mediator)
[Authorize]
[HttpGet("GetAll")]
public async Task<IActionResult> Index()
{
return Ok(await Mediator.Send(new GetAllClientQuery()));
}
}
Now, you can Mock IMediator as you normally would.
Related
I defined a custom repository Interface which get stream of entities through Query.getResultStream
public interface MyRepository<T> {
Stream<T> findByCriteria(...);
}
public class MyRepositoryImpl<T> implements MyRepository<T> {
#Autowired SessionFactory sessionFactory;
public Stream<T> findByCriteria(...) {
...
}
}
and my Repository & Service
#Repository
public interface EntityRepository extends MyRepository<Entity> {
...
}
#Service
#Transactional(readOnly = true)
public class EntityService {
#Autowired EntityRepository entityRepository;
public Stream<Entity> getEntitiesByCriteria(String criteria) {
...
return entityRepository.findByCriteria(...);
}
}
Problem is my Service Unit Test does not see the repository implementation, and always return null without going inside findByCriteria implementation.
ExtendWith(MockitoExtension.class)
class EntityServiceTest {
#InjectMocks EntityService service;
#Mock EntityRepository repository;
#Test
void test() {
...
when(repository.findByCriteria(...))
.thenReturn(...);
service.getEntitiesByCriteria(...); //This does not see the implementation of findByCriteria in MyRepositoryImpl
]
}
I tried many annotations like #RepositoryDefinition in my interface or #EnableJpaRepositories in my test class but nothing seems to work
Having some issues getting my repository to retrieve information - keeps coming back null. Any Thoughts would be appreciated - new to this and teaching myself.
Repository:
public class CustomerRepository : ICustomerRepository
{
private masterContext context;
public CustomerRepository(masterContext context)
{
this.context = context;
}
public IEnumerable<Customer> GetCustomers()
{
return context.Customer.ToList();
}
public Customer GetCustomerById(int customerId)
{
var result = (from c in context.Customer where c.CustomerId == customerId select c).FirstOrDefault();
return result;
}
public void Save()
{
context.SaveChanges();
}
Controller:
public class CustomerController : Controller
{
private readonly ICustomerRepository _repository = null;
public ActionResult Index()
{
var model = (List<Customer>)_repository.GetCustomers();
return View(model);
}
public ActionResult New()
{
return View();
}
}
MasterContext which i had efc make:
public partial class masterContext : DbContext
{
public masterContext(DbContextOptions<masterContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.CustomerName).IsRequired();
});
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Order> Order { get; set; }
}
I think you need to create instances of you Context and your Repository. So in your Controller you need to something like this:
private masterContext context = new masterContext();
private ICustomerRepository repository = new CustomerRepository(context);
I assume that you're not using Dependency injection ... if so you just need to create a Constructor for your Controller that takes CustomerRepository as argument:
public CustomerController(ICustomerRepository _repository) {
repository = _repository;
}
If you did not configure your database context, look here: https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html
This will than enable you the dependency injection. Everything you than need to do for the Repository is to use
services.AddScoped<ICustomerRepository,
CustomerRepository>();
And I think it could be good to remove the ToList() in the Repository class and remove the Cast List<Customer> in your Controller and use ToList() instead, if it's really needed. Because if you're using it in the View the ienumerable could also work.
I have a simple Http module:
public class CustomLoggingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public void BeginRequest(object sender, EventArgs eventArgs)
{
//some code
}
public void EndRequest(object sender, EventArgs eventArgs)
{
//some
}
public void Dispose()
{
}
}
How can I unit test this? Especially how is it possible to mock events? Can anyone give some simple example?
Not sure why you have decided to hardwire the dependencies as new LogService() and new HttpContextWrapper(HttpContext.Current) within the CustomLoggingModule. If want to test whether LogInfo() method is called or not, it becomes lot easier if you can externalize these dependencies so you can inject stubbed/mocked version etc.
Also your question does not state that you are using an IOC container. You can register the HttpModule with the container and provide external dependencies at runtime. Your question also does not state that using an isoloation/mock object framework.
Therefore I will provide you with a solution that you can verify whether LogInfo method is called, using hand written stubs and mocks.
To achieve this, we need to refactor CustomLoggingModule a bit, so it becomes more testable.
System Under Test (SUT)
public class CustomLoggingModule : IHttpModule
{
public ILogService LogService { get; set; }
public Func<ILoggingHttpContextWrapper> LogginHttpContextWrapperDelegate { get; set; }
public void Init(HttpApplication context) {
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public CustomLoggingModule() {
LogginHttpContextWrapperDelegate = () => new LoggingHttpContextWrapper();
}
public void BeginRequest(object sender, EventArgs eventArgs) {
LogService.LogInfo(LogginHttpContextWrapperDelegate().HttpContextWrapper);
}
public void EndRequest(object sender, EventArgs eventArgs) {
//some
}
public void Dispose(){ }
}
As you see above, I have introduced 2 additional properties - ILogService so I can provide a Mocked verion and a delegate Func which allows me to stub the
new HttpContextWrapper(HttpContext.Current);
public interface ILoggingHttpContextWrapper {
HttpContextWrapper HttpContextWrapper { get; }
}
public class LoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public LoggingHttpContextWrapper() {
HttpContextWrapper = new HttpContextWrapper(HttpContext.Current);
}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
And then your real ILogService
public interface ILogService {
void LogInfo(HttpContextWrapper httpContextWrapper);
}
public class LogService : ILogService {
public void LogInfo(HttpContextWrapper httpContextWrapper)
{
//real logger implementation
}
}
Unit Test :
You would create a MockLoggerService, so you can verify the interaction i,e whether the LogInfo() method was called, etc. You also need a stubbed LoggingHttpContextWrapper to provide the fake HttpContextWrapper to the SUT (System Under Test)/ CustomLoggingModule.
public class StubLoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public StubLoggingHttpContextWrapper(){}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
public class MockLoggerService : ILogService
{
public bool LogInfoMethodIsCalled = false;
public void LogInfo(HttpContextWrapper httpContextWrapper) {
LogInfoMethodIsCalled = true;
}
}
MockLoggerService is very important. It is not the real logger service, but it is the mocked version. When we do public class MockLoggerService : ILogService this means that we are providing another layer of indirection to the logger service so we can verify the interaction of the behaviour.
You also notice that I have provided a boolean variable to verify whether the LogInfo method is called or not. This allows me to call this method from the SUT, and verify whether the method being called or not.
Now Your Unit Test can be implemented as below.
[TestMethod]
public void CustomLoggingModule_BeginRequest_VerifyLogInfoMethodIsCalled()
{
var sut = new CustomLoggingModule();
var loggerServiceMock = new MockLoggerService();
var loggingHttpContextWrapperStub = new StubLoggingHttpContextWrapper();
sut.LogService = loggerServiceMock;
sut.LogginHttpContextWrapperDelegate = () => loggingHttpContextWrapperStub;
sut.BeginRequest(new object(), new EventArgs());
Assert.IsTrue(loggerServiceMock.LogInfoMethodIsCalled);
}
I had the same issue with my custom http module and decided I won't give up that easily and will do all I can to trigger the BeginRequest event in unit test. I had to actually read through the source code of HttpApplication class and use reflection to invoke the method.
[TestMethod]
public void EventTriggered_DoesNotError()
{
using (var application = new HttpApplication())
{
var module = new CustomLoggingModule();
module.Init(application);
FireHttpApplicationEvent(application, "EventBeginRequest", this, EventArgs.Empty);
}
}
private static void FireHttpApplicationEvent(object onMe, string invokeMe, params object[] args)
{
var objectType = onMe.GetType();
object eventIndex = (object)objectType.GetField(invokeMe, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandlerList events = (EventHandlerList)objectType.GetField("_events", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandler handler = (EventHandler)events[eventIndex];
Delegate[] delegates = handler.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, args);
}
}
I have a set of classes to work with REST methods in project. They look like this:
#Path("customer/")
#RequestScoped
public class CustomerCollectionResource {
#EJB
private AppManager manager; // working with DB
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response list(#QueryParam("email") String email) {
final List<Customer> entities = manager.listCustomers(email);
// adding customers to result
return Response.ok(result).build();
}
}
After that I've wrote test method:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test #GET #Path("projectName/customer") #Consumes(MediaType.APPLICATION_JSON)
public void test(ClientResponse<List<Customer>> response) throws Exception {
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
}
And I get NullPointerException when trying to run this test. It's because of empty response in test case. Why is this happens? DB is configured properly.
There are two modes an arquillian test can run: in-container and client mode. HTTP interfaces can be tested only in client mode (never tried the extensions, only used vanilla Arquillian for this).
By default the test methods executed in the context of the container, called by the arquillian test runner servlet.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean; // EJBs can be injected, also CDI beans,
// PersistenceContext, etc
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test
public void some_test() {
bean.checkSomething();
}
}
In client mode, the test methods are running outside of the container, so you don't have access to EJBs, EntityManager, etc injected into the test class, but you can inject an URL parameter for the test method.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
// testable = false here means all the tests are running outside of the container
#Deployment(testable = false)
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
// baseURI is the applications baseURI.
#Test
public void create_account_validation_test (#ArquillianResource URL baseURI) {
}
You can use this URL parameter to build URLs to call your HTTP service using whatever method you have, like the new JAX-RS client API.
You can also mix the two modes:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean;
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
}
#Test
#InSequence(0)
public void some_test() {
bean.checkSomething();
}
#Test
#RunAsClient // <-- this makes the test method run in client mode
#InSequence(1)
public void test_from_client_side() {
}
}
This is sometimes even necessary, because some extensions, like persistence cannot run in client mode.
I am using RestEasy to develop a REST server and using the mock dispatcher (org.jboss.resteasy.mockMockDispatcherFactory) for testing the service in my unit tests. My service requires digest authentication and I would to make that part of my testing.
Each of my services accepts a #Context SecurityContext securityContext parameter.
Is there any way is inject a fake SecurityContext in the dispatcher so that I can test that my security methods function properly?
You have to add the SecurityContext into the context data map in ResteasyProviderFactory.
public class SecurityContextTest {
#Path("/")
public static class Service {
#Context
SecurityContext context;
#GET
public String get(){
return context.getAuthenticationScheme();
}
}
public static class FakeSecurityContext extends ServletSecurityContext {
public FakeSecurityContext() {
super(null);
}
#Override
public String getAuthenticationScheme() {
return "unit-test-scheme";
}
}
#Test
public void securityContextTest() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(new Service());
ResteasyProviderFactory.getContextDataMap().put(SecurityContext.class, new FakeSecurityContext());
MockHttpRequest request = MockHttpRequest.get("/");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals("unit-test-scheme", response.getContentAsString());
}
}
For those coming across this issue today, adding Contexts has been moved from the RestEasyProviderFactory class into the Dispatcher class using getDefaultContextObjects() method.
I've edited the old answer with the new call:
public class SecurityContextTest {
#Path("/")
public static class Service {
#Context
SecurityContext context;
#GET
public String get(){
return context.getAuthenticationScheme();
}
}
public static class FakeSecurityContext extends ServletSecurityContext {
public FakeSecurityContext() {
super(null);
}
#Override
public String getAuthenticationScheme() {
return "unit-test-scheme";
}
}
#Test
public void securityContextTest() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(new Service());
dispatcher.getDefaultContextObjects().put(SecurityContext.class, new FakeSecurityContext());
MockHttpRequest request = MockHttpRequest.get("/");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals("unit-test-scheme", response.getContentAsString());
}
}