Custom ConstraintValidator unit test using Quarkus - constraints

I need to make validations on my custom ConstraintValidator that uses an #Inject needed for some validations, it's like this example from quarkus https://quarkus.io/guides/validation
#ApplicationScoped
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
#Inject
MyService service;
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return service.validate(value);
}
}
When i run the application I see that is made the right validation, but i'm trying to make unit test using mockito i can't mock the object is always null on the default using the Default Bean validation.
On the example from quarkus is unit test only for integration.
this is my implementation
#ApplicationScoped
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
#Inject
BookService service;
#ConfigProperty(name = "my.property")
int myLimit;
public MyConstraintValidator(BookService service) {
this.service = service;
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("myLimit property: " + myLimit);
int limit = Integer.parseInt(value);
if (limit < myLimit) {
return service.validate(value);
} else {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(NAME_EMPTY).addConstraintViolation();
return false;
}
}
}
Unit test for testing the custom Validator
#Test
void testAmountValidationWithContext() {
BookRequest bookRequest = new BookRequest();
bookRequest.setTitle("my title");
bookRequest.setAuthor("my Author");
bookRequest.setPages(2L);
bookRequest.setAmount("11");
//when:
myConstraintValidator = new MyConstraintValidator(service);
Mockito.when(service.validate(anyString())).thenReturn(true);
//then:
Set<ConstraintViolation<BookRequest>> violations = validator.validate(bookRequest);
// verify that the context is called with the correct argument
Mockito.verify(context).buildConstraintViolationWithTemplate(NAME_EMPTY);
}
The unit test to test the default #NoBlank.
#Test
void testBeanValidationWithInvalidAmount() {
BookRequest bookRequest = new BookRequest();
bookRequest.setTitle("my title");
bookRequest.setAuthor("my Author");
bookRequest.setPages(2L);
bookRequest.setAmount("AA");
//when:
Set<ConstraintViolation<BookRequest>> violations = validator.validate(bookRequest);
//then:
assertEquals(1, violations.size());
assertEquals(NOT_EMPTY, violations.stream().findFirst().get().getMessage());
}
The first unit test works weel, i can mock the object and test the result.
The problem is on my second test, when i try to test the other validations #NotNull, #Pattern. On this test the method isValid() is also invoked and here it's my problem because the #ConfigProperty and the #Inject are always null, and i can't mocked them.
I already saw several examples over internet but doesn't work and are almost for spring but i need to make the custom validation on quarkus.
How can i implement the custom ConstraintValidator unit test using quarkus?
Does any one have any example with this working?

Changing your code from field injection to constructor injection will make unit testing much easier.
#ApplicationScoped
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
private final MyService service;
private final int myLimit;
public MyConstraintValidator(MyService service, #ConfigProperty(name = "my.property") int myLimit) {
this.service = service;
this.myLimit = myLimit;
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context)
{
if (value == null) {
return true;
}
return service.validate(value);
}
}

Updated description with my implementations.
but resuming the issue.
when i have the default annotations with my custom validator i can't mock the objects using the
Set<ConstraintViolation<BookRequest>> violations = validator.validate(bookRequest);

Related

An error occurred when trying to create a controller of type 'XXXXController'. Make sure that the controller has a parameterless public constructor

I have created a asp.net web api project and implemented the below HTTP GET method in AccountController and the related service method & repository method in AccountService & AccountRepository respectively.
// WEB API
public class AccountController : ApiController
{
private readonly IAccountService _accountService;
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
[HttpGet, ActionName("UserProfile")]
public JsonResult<decimal> GetUserSalary(int userID)
{
var account = _accountService.GetUserSalary(userID);
if (account != null)
{
return Json(account.Salary);
}
return Json(0);
}
}
Service / Business Layer
public interface IAccountService
{
decimal GetUserSalary(int userId);
}
public class AccountService : IAccountService
{
readonly IAccountRepository _accountRepository = new AccountRepository();
public decimal GetUserSalary(int userId)
{
return _accountRepository.GetUserSalary(userId);
}
}
Repository / Data Access Layer
public interface IAccountRepository
{
decimal GetUserSalary(int userId);
}
public class AccountRepository : IAccountRepository
{
public decimal GetUserSalary(int userId)
{
using (var db = new AccountEntities())
{
var account = (from b in db.UserAccounts where b.UserID == userId select b).FirstOrDefault();
if (account != null)
{
return account.Salary;
}
}
return 0;
}
}
UnityConfig
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IAccountService, AccountService>();
container.RegisterType<IAccountRepository, AccountRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
But when I invoke the API method GetUserSalary() I get an error saying
An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.
Check that you did not forget to register Unity IoC container itself:
if you use ASP.NET Framework it could be - Global.asax or Startap.cs (Owin) via UnityConfig.RegisterComponents() method.
if you use ASP.NET Core then in the Startup.cs file (I was unable to find official guides for its configuting)
Your current constructor has parameters (or args if you prefer).
see:
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
All you need to do is add a "Parameter-less Constructor" into the controller as well.
public AccountController()
{
}
Parameter-less constructors are usually above the ones that have params, though as far as I am aware this is only due to standards not any actual effect(s) it may cause.
There is also an already existing issue/question similar to this I will link below that may provide further details.
Make sure that the controller has a parameterless public constructor error

When do we need data classes?

Im using asp.net core. Here is the basic way to use model with controller.
public class BookController : Controller
{
private readonly ApplicationDbContext _context { get; set; }
public BookController(ApplicationDbContext context)
{
_context = context;
}
public IActionResult Create(Book model)
{
// adding new model
}
public IActionResult Edit(Book model)
{
// modifying the model
}
public IActionResult Delete(Book model)
{
// removing the model
}
}
My question: when shall/should I implement the code inside the controller? When shall/should I implement it in another class?
Something like this:
public interface IBook
{
int Add(Book book);
int Update(Book book);
int Remove(Book book);
}
public class BookData : IBook
{
private readonly ApplicationDbContext _context { get; set; }
BookData(ApplicationDbContext context)
{
_context = context
}
public int Add(Book model)
{
// ...
return _context.SaveChanges();
}
// other implements...
}
Then, calling it inside controller:
public IActionResult Create(Book model)
{
var bookData = new BookData(_context);
int result = bookData.Add(model);
// ...
}
For the interface, I think it may be useful for the case: I have many controllers that require same action/method names.
Example: MessageController requires 3 actions/methods at least (Create/Add, Edit/Update, Delete/Remove). It's same to NotificationController class, CommentController class...
So, the interface can be improved to:
public interface IMyService<T> where T : class
{
int Add(T model);
int Update(T model);
int Remove(T model);
}
public class MyService<T> : IMyService<T> where T : class
{
private readonly ApplicationDbContext _context { get; set; }
public MyService(ApplicationDbContext context)
{
_context = context;
}
public int Add(T model)
{
Type type = typeof(model);
if (type == typeof(Book))
{
// adding new book model
}
else if (type == typeof(Comment))
{
// adding new comment model
}
// ...
return -1;
}
// other implements...
}
Do I misunderstand something?
If I read it correctly with data classes you actually means repository (which is an abstraction over the persistence layer). You should always encapsulate persistence logic behind a class (be it via repository pattern, command/query pattern or request handler) and use it instead of directly using the context in your service classes.
That being said, you can directly inject your BookData to your controller instead of the ApplicationDbContext. One thing you should consider you lose in your current implementation is the Unit of Work pattern. Right now, every add will instantly persist the data.
This may not be what you want, so you should move the _context.SaveChanges(); outside of the Add/Remove/Update methods and call it explicitly. This allows you to insert i.e. 10 records and if one of them fails, nothing will be persisted to the database.
But if you call _context.SaveChanges(); after each insert and you get an error in the 8th (of 10) records, then 7 get persisted and 3 will be missing and you get inconsistent data.
Controller shouldn't contain any logic at all, only do short validation of the input model (ModelState.IsValid check) and if its okay, call the services which do all the logic and report the result back to the user. Only in very simple tutorials and guides logic is put into the controller action for reasons of simplicity. In real world applications you should never do that. Controllers are much harder to unit test than service classes.

why #autowired in spring does not need setter method for private instance variable?

I have some code in my spring project as below
#Component
public class DatabaseAccessUtil
{
#Autowired
private DatabaseAccessor databaseAccessor;
}
My concern is how and why #Autowired annotation of spring work without setter method, example:
void setDatabaseAccessor(DatabaseAccessor databaseAccessor)
{
this.databaseAccessor = databaseAccessor;
}
where is spring's miracle? Thanks
It is because the value of the field is injected via Reflection. Field, Method and Constructor are all descendants of java.lang.reflect.AccessibleObject. This class permits access to its private members by setting the accessible flag to true by calling setAccessible(true).
Here is the actual code from AutowiredBeanPostProcessor that does the actual injection
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
And the source code of ReflectionUtils.makeAccessible(Field)
public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers()) ||
Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
}

CDI Injection and #Model Annotation

I have two questions regarding two annotations:
1) Why does the "faceContext" has to be injected from Resources class? Instead, MemberController can directly use "FacesContext.getCurrentInstance()" in register() method to obatin a FacesContext object? It seems much simpler to do that.
2) Can #Model be replaced by #Singleton? Or even #ApplicationScoped?
Thanks.
MemberController.java
#Model
public class MemberController {
#Inject
private FacesContext facesContext;
#Inject
private MemberRegistration memberRegistration;
#Produces
#Named
private Member newMember;
#PostConstruct
public void initNewMember() {
newMember = new Member();
}
public void register() throws Exception {
try {
memberRegistration.register(newMember);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_INFO, "Registered!", "Registration successful");
facesContext.addMessage(null, m);
initNewMember();
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, "Registration unsuccessful");
facesContext.addMessage(null, m);
}
}
}
Resources.java
public class Resources {
// use #SuppressWarnings to tell IDE to ignore warnings about field not being referenced directly
#SuppressWarnings("unused")
#Produces
#PersistenceContext
private EntityManager em;
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
#Produces
#RequestScoped
public FacesContext produceFacesContext() {
return FacesContext.getCurrentInstance();
}
}
injecting the FacesContext istead of getting it using the static factory method has the advantage that you will only once have to care about how to get the current context, when implementing the producer method or field. Each time you need the context you can simply inject it and it is fully transparent to you where it comes from. This might also have some benefits when anything changes in how to get the context, ...
The answer to the second question depends on your requirements. Since #Model is simply a stereotype for #RequestScoped and #Named, you cannot directly replace it with #Singleton or #ApplicationScoped since these both annotations adwise the container to create a single object for all requests. Nevertheless, if this meets your requirements better than having a different object for each request, you are free to change it ;)

Mock #org.jboss.seam.annotations.in behaviour for unittest

The test:
public class BeanTest {
private SomeBean target;
#Test(groups = "integration")
public void checkIfAuthenticationWorks() {
ApplicationBean applicationBean = mock(ApplicationBean.class);
target = new SomeBean();
// Some cool code to inject applicationBean to target class
assertEquals("token", target.authenticate(USERNAME, PASSWORD));
}
}
The class:
#AutoCreate
#Name("someBean")
#Scope(ScopeType.SESSION)
public class someBean implements Serializable {
#Logger
private static Log log;
#In
ApplicationBean applicationBean;
public String authenticate(String username, String password) {
// Very cool code!
return "token";
}
}
Is there some smart way of solving the applicationBean injection part?
// Jakob
First, make the test the Seam way, that is extending SeamTest:
public class BeanTest extends SeamTest {
private SomeBean target;
#Test(groups = "integration")
public void checkIfAuthenticationWorks() {
target = (SomeBean) Component.getInstance(SomeBean.class);
// target get injected with the MockApplicationBean
assertEquals("token", target.authenticate(USERNAME, PASSWORD));
}
}
Then, create a MockApplicationBean with MOCK precedence and put it in the test classpath so that it will be injected in place of the real ApplicationBean:
#Name("applicationBean")
#Install(precedence = MOCK)
public class MockApplicationBean extends ApplicationBean
{
// your mocked ApplicationBean
}
Finally, note that target must be instantiated as a Seam component, not with "new":
SomeBean target = (SomeBean) Component.getInstance(SomeBean.class);

Resources