Mock methods of a class not given by DI - .net-core

I have a class I am trying to test. The class constructor has a class that is injected and another class that is initialized in the constructor. The second class comes from an external source.
public class MyClass
{
private readonly ILogger<MyClass> _logger;
private readonly MavlinkParse _mavlink;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
_mavlink = new MavlinkParse();
}
}
Later I have a method where I call the _mavlink methods based on a condition. I want to somehow mock the methods, or better yet just "spy" on them and know which was called.
The method:
public SomeMethod(input)
{
if(cond)
return _mavlink.method1(lots of params);
return _mavlink.method2(lots of params);
}
I know how to mock the logger using xunit and moq. What I am stuck on is how to test SomeMethod().
I come from the angular world, where I could easily solve this issue with a spy, and expect(method1Spy).toHaveBeenCalled() would be perfect. I would also be able to settle for the idea of having method1() return a hard-coded value, ignoring params, and check that that came through
How can I achieve this effect in c# dotnet core using xunit and moq?

Related

Dependency injection in my singleton class .NET Core

I'm having trouble injecting the dependency I pass into the constructor of my Asegurador class.
When I want to instantiate, _instance = new Asegurador(); I don't have the parameter required by the constructor (IGeneralRepository), how can I solve this problem?
Note that my Asegurador class is a singleton.
private Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result;
_repository = generalRepository;
}
public static Asegurador Instance
{
get
{
if (_instance == null)
{
_local = System.Environment.GetEnvironmentVariable("SEGUROS_LOCAL") ?? "local";
_instance = new Asegurador();
}
return _instance;
}
}
When using a DI container you can (and should) let it take care of handling the Lifetime of a dependency.
.Net core's dependency injection lets you define 3 different lifetimes for your services (Docs):
Transient: a transient service is recreated each time it is injected
Scoped: a scoped service is created once for each request
Singleton: a singleton is created once in the whole application lifetime.
The best approach to achieve what you are trying to do is the following:
Amend your Asegurador class so that it has a public constructor and get rid of the static Instance property
public class Asegurador {
public Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result; //I know too few about it but I would try to pass it as a dependency as well
_repository = generalRepository;
}
}
instead of calling Asegurador.Instance inject the dependency in the client class
public class IUseTheAsegurador {
private Asegurador _asegurador;
public IUseTheAsegurador(Asegurador asegurador)
{
_asegurador = asegurador;
}
}
Register all in the DI in your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<Asegurador>();
services.AddScoped<IUseAsegurador>(); //This can be Singleton or Transient as well, depending on your needs
...
}
I (a lot of people actually :D) prefer this approach because it leaves the responsability of guaranteeing a single instance to the DI and also because lets you write unit tests for the client class (IUseTheAsegurador in the example) in an easier way.

CDI and JavaFX (javafx-weaver) Integration

After reading some articles about the CDI and Java FX integration, and the source codes of javafx-weaver spring integration.
I decided to add CDI integration to Java FX via the existing javafx-weaver work to simplify the integration work.
The source code can be found here.
I added a simple producer to expose FxWeaver to the CDI context.
#ApplicationScoped
public class FxWeaverProducer {
private static final Logger LOGGER = Logger.getLogger(FxWeaverProducer.class.getName());
#Produces
FxWeaver fxWeaver(CDIControllerFactory callback) {
var fxWeaver = new FxWeaver((Callback<Class<?>, Object>) callback,
() -> LOGGER.log(Level.INFO, "calling FxWeaver shutdown hook")
);
return fxWeaver;
}
public void destroyFxWeaver(#Disposes FxWeaver fxWeaver) {
LOGGER.log(Level.INFO, "destroying FxWeaver bean...");
fxWeaver.shutdown();
}
}
The problem is when using fxWeaver.loadView to load view, the controller did not work as expected.
#ApplicationScoped
#FxmlView("HandlingReport.fxml")
public class HandlingReportController {
private final static Logger LOGGER = Logger.getLogger(HandlingReportController.class.getName());
#Inject
private HandlingReportService handlingReportService;
//fxml properties...
#FXML
private void onSubmit(){...}
}
As above codes, the dependent service handlingReportService in the controller class is null(not injected) when performing an action like onSubmit, it seems when JavaFX handles the #FXML properties binding it always used java reflection API.
If I change the method to public void onSubmit()( use public modifier), all FX fields become null when pressing the onSubmit button.
Any idea to fix this issue?
Marked the controller class as #Dependentscope to resolve the problem.
#Dependent
public class HandlingReportController { ...}

Mockito failure: Actually, there were zero interactions with this mock

I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;
#RestController
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
#RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
List<ResponseModel> timezones = employeeService.fetchTimeZones();
return new ResponseEntity<>(timezones, HttpStatus.OK);
}
}
The following is my test class;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfiguration.class})
#WebAppConfiguration
public class EmployeeRestControllerUnitTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private EmployeeService employeeService;
#InjectMocks
private EmployeeRestController employeeRestController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
#Test
#WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
try {
mockMvc.perform(get("/fetch-timezones"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(4)));
verify(emploeeService, times(1)).fetchTimeZones();
verifyNoMoreInteractions(employeeService);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.
I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using #InjectMocks, then why i'm getting the following failure;
Wanted but not invoked:
careGroupService.fetchTimeZones();
-> at com.example.api.test
.restcontroller.EmployeeRestControllerUnitTest
.testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
Actually, there were zero interactions with this mock.
How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.
I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.
Finally, how does this piece of code: Mockito.reset(employeeService); works.
1) you do verify for
verify(emploeeService, times(1)).fetchTimeZones();
but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).
List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );
2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.
It stands up the Dispatcher Servlet and all required MVC components,
allowing us to test an endpoint in a proper web environment, but
without the overhead of running a server.
3) when you use:
#MockBean private EmployeeService employeeService;
you override real service. remove it from test class real service will be used in testing. Instead of use #Mock use #MockBean. #MockBean it's override by container, with #Mock you need to inject this into controller by reflection
or without spring boot with reflection:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
EmployeeRestController employeeRestController=
webAppContext.getBean(EmployeeRestController.class);
ReflectionTestUtils.setField(employeeRestController,
"employeeService",
employeeService);
}
4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.

AspNetCore Middleware UserManager Dependency Injection

I have a multi-layer application that I started writing in ASP.NET Core 1.1 which I'm still learning along the way. I have organized it like previous apps I've done in the Web API, I have host service (net core app), business layer and data layer that is above database. Business and data layers were net core standard libraries, but when I wanted to add entity framework I had to modify data layer to look like net core app, so now I have Startup.cs with configurations there. That allowed me to configure entity framework service and to create migrations in the data layer. But now I have a problem as I wanted to add asp.net identity. Every tutorial on the net is about SPAs that have everything in one project.
I have added identity to Startup.cs and database is generated well
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddEntityFramework(connectionString);
services.AddMyIdentity();
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
// User settings
options.User.RequireUniqueEmail = true;
});
}
public void Configure(IApplicationBuilder app)
{
app.UseIdentity();
}
but now I need to use UserManager from a class that is not a Controller and I don't know how to deal with dependency injection.
To explain better, I have an Account controller in my Host Service
[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody]RegisterUserDto dto)
{
var result = await Business.Commands.Accounts.Register(dto);
return Ok(result);
}
Business layer just calls the Data layer
public async static Task<ResponseStatusDto> Register(RegisterUserDto dto)
{
// some code here
var identityLogon = await Data.Commands.ApplicationUsers.Register(dto);
// some code here as well
return new ResponseStatusDto();
}
Now the question is, how do I get UserManager in the Data Register method? It's a simple class, it doesn't inherit from a controller, dependency injection is not working for constructors like in the examples found here
Core Identity
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private static bool _databaseChecked;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
//
// GET: /Account/Login
So, how do I pass UserManager that is configured in Startup to some random class somewhere in the middleware? I have seen this question, but the answer to just pass null values to UseManager constructor is not working nor I think it's good.
//EDIT as per Set's answer
I have removed all static references, but I'm still not quite there. I have followed this dependency injection instructions, but I'm not sure how to instantiate and call Add method.
I have created an interface
public interface IIdentityTransaction
{
Task<IdentityResult> Add(ApplicationUser appUser, string password);
}
and implemened it
public class IdentityTransaction : IIdentityTransaction
{
private readonly ApplicationDbContext _dbContext;
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public IdentityTransaction(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
{
_roleManager = roleManager;
_userManager = userManager;
_dbContext = context;
}
public async Task<IdentityResult> Add(ApplicationUser applicationUser, string password)
{
return await _userManager.CreateAsync(applicationUser, password);
}
}
then I injected it to a service collection in Startup.cs
services.AddScoped<IIdentityTransaction, IdentityTransaction>();
but how to call Add method from IdentityTransaction service?
I cannot instantiate it nor use dependency injection on constructor as it just loops my problem. #Set mentioned
or pass UserManager userManager as parameter to method
pass it from where?
I think I'm very close, but I'm missing something.
I have tried using
IIdentityTransaction it = services.GetRequiredService<IIdentityTransaction>();
but services which is IServiceProvider is null, I don't know where to get it from either.
DI in ASP.NET Core works the same for controller and non-controller classes using "constructor injection" approach.
You have the problem as Register method is static, so doesn't have access to instance variables/properties. You need to
make Register method non-static
or pass UserManager<ApplicationUser> userManager as parameter to method
In general, you should avoid using static classes for business logic as they don't help to test your code properly and produce the code coupling. Search via internet/SO and you will find a lot of topics why static is bad.
Use DI to get the instance of Data.Commands.ApplicationUsers class in your controller. If you need only one instance of this class for your application - use singleton lifetime for it.
Update. Again, use constructor injection: modify your "Data Layer" class so it can get the instance of IIdentityTransaction as constructor parameter:
public class YourDataLayerClass : IYourDataLayerClass
{
private IIdentityTransaction _identityTransaction;
public YourDataLayerClass(IIdentityTransaction identityTransaction)
{
_identityTransaction = identityTransaction;
}
public void MethodWhereYouNeedToCallAdd()
{
_identityTransaction.Add(...);
}
}
And idea the same for IYourDataLayerClass instance: register dependency
services.AddScoped<IYourDataLayerClass, YourDataLayerClass>();
and then the class (middleware in your case, if I understand you properly) that depends on it should receive that instance via constructor:
public class YourMiddleware
{
private IYourDataLayerClass _yourDataLayerClass;
public YourMiddleware(IYourDataLayerClass yourDataLayerClass)
{
_yourDataLayerClass = yourDataLayerClass;
}
...
}
Yes you are very close.
First thing, either remove context parameter from the IdentityTransaction constructor as in your code snipped it appears to be useless. Or if you plan to use it later, declare it in the DI container:
services.AddScoped<ApplicationDbContext, ApplicationDbContext>();
Second thing, you simply need to add IIdentityTransaction as a dependency in the controller's constructor, and remove SignInManager and UserManager from its dependencies as eventually you won't use these directly within the controller:
public class AccountController : Controller
{
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private static bool _databaseChecked;
private readonly ILogger _logger;
IIdentityTransaction _identityTransaction;
public AccountController(
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
IIdentityTransaction identityTransaction)
{
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_identityTransaction = identityTransaction;
}
If you need an additional business layer (IBusinessLayer) between the controller, same process, declare the class in the DI container at startup, add IIdentityTransaction as a dependency in the business class constructor, and update the controller's dependencies from IIdentityTransaction to IBusinessLayer.
A couple more precisions.
services.AddScoped<IIdentityTransaction, IdentityTransaction>();
This piece of code does NOT inject instances or dependencies. It declares an interface and its associated implementation in the DI container, so it can be injected later when required. Actual instances are injected when the objects that required them are actually created. I.e. the controller gets its dependencies injected when it is instantiated.
IIdentityTransaction it = services.GetRequiredService<IIdentityTransaction>();
What you tried to do here is called the dependency locator pattern, and is often considered as an anti-pattern. You should stick to dependency injection via the constructor, it's much cleaner.
The key is to declare everything in the DI container at startup, even your custom business/data layers classes, never instantiate them yourself anymore, and declare them as required dependencies in any classes' constructor that need them.

best way to integration test spring mvc

I have a Spring MVC 3.2 project that I would like to unit & integration tests. The problem is all the dependencies I have, makes testing extremely difficult even with Sprint-test.
I have a controller like this:
#Controller
#RequestMapping( "/" )
public class HomeController {
#Autowired
MenuService menuService; // will return JSON
#Autowired
OfficeService officeService;
#RequestMapping( method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )
#ResponseBody
public AuthenticatedUser rootCall( HttpServletRequest request ) {
AuthenticatedUser authentic = new AuthenticatedUser();
Office office = officeService.findByURL(request.getServerName());
authentic.setOffice(office);
// set the user role to authorized so they can navigate the site
menuService.updateVisitorWithMenu(authentic);
return returnValue;
}
This will return a JSON object. I would like to test this call returns a 200 and the correct object with canned JSON. However, I have a lot of other classes called by those #Autowired classes, and even if I mock them like this:
#Bean public MenuRepository menuRepository() {
return Mockito.mock(MenuRepository.class);
}
this creates a lot of mocked classes. Here is how I am trying to test it:
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( classes = JpaTestConfig.class )
#WebAppConfiguration
public class HomeControllerTest {
private EmbeddedDatabase database;
#Resource
private WebApplicationContext webApplicationContext;
#Autowired
OfficeService officeService;
private MockMvc mockMvc;
#Test
public void testRoot() throws Exception { mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().contentType(IntegrationTestUtil.APPLICATION_JSON_UTF8))
.andExpect(content().string(<I would like canned data here>));
}
I can go thru and setup a H2 embeddeddatabase and populate it, but I wonder if that is really a test of this controller or the application? Can anyone recommend some better approaches to this integration test? How does one write unit tests for controllers?
Thank you!
Check out the spring show case project and take a look at controller test cases you will be able to understand and see standard way of testing controllers. MappingControllerTests.java has some json based controller testing

Resources