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);
Related
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);
I am trying to write a unit test for the below Assembler but i keep getting Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?. I wanted to know how i can mock out the resource creation?
#Component
public class LoginResourceAssembler extends ResourceAssemblerSupport<User, ResourceSupport> {
public LoginResourceAssembler() {
super(User.class, ResourceSupport.class);
}
#Override
public ResourceSupport toResource(User user) {
ResourceSupport resource = new ResourceSupport();
final String id = user.getId();
resource.add(linkTo(MyAccountsController.class).slash(id).slash("accounts").withRel("accounts"));
return resource;
}
}
Instead of changing from a plain unit test to a IMO integration test (given dependency of the spring framework) you could do something like:
#RunWith(MockitoJUnitRunner.class)
public class LoginResourceAssemblerTest {
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
}
#Test
public void testToResource() {
//...
}
}
I was seeing the error Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler because my test class was annotated with #RunWith(MockitoJUnitRunner.class) and this was not injecting the controller.
To fix this error, i annotated my test case with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
A working test case in my case
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class LoginResourceAssemblerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testToResource() {
User user = new User();
user.setId("1234");
ResourceSupport resource = loginResourceAssembler.toResource(user);
assertEquals(1,resource.getLinks().size());
assertEquals("accounts",resource.getLinks().get(0).getRel());
assertTrue(resource.getLinks().get(0).getHref().contains("accounts"));
}
}
I'm using SpringBoot and I am trying to create a service layer for my web application but i cant make it work.
My classes look like this
ServiceFactory
#Service
public class ServiceFactory {
#Autowired
public static EncuestaService getEncuestaService()
{
return new EncuestaServiceImpl();
}
}
EncuestaService
public interface EncuestaService {
void crearEncuesta(Encuesta encuesta, Map<String,String> parametros);
}
EncuestaServiceImpl
#Service
public class EncuestaServiceImpl implements EncuestaService {
#Override
public void crearEncuesta(Encuesta encuesta, Map<String, String> parametros) {
CrearEncuesta nueva = new CrearEncuesta(encuesta,parametros);
nueva.execute();
}
}
CrearEncuesta
#Service
public class CrearEncuesta {
private Encuesta encuesta;
private Map<String,String> parametros;
#Autowired
private RespuestasRepository respuestasRepository;
#Autowired
private EncuestasRepository encuestasRepository;
public CrearEncuesta(Encuesta encuesta, Map<String,String> parametros) {
super();
this.encuesta = encuesta;
this.parametros = parametros;
}
public void execute()
{
encuestasRepository.save(encuesta);
}
}
Everytime I call ServiceFactory.getEncuestasService().crearEncuesta() from any Controller it returns me a NullPointerException.
From what I have been reading I should not be creating a new EncuestsaServiceImpl() in my ServiceFactory but I don't really know the correct way to do so. I would appreciate if anyone could help me out :P.
Edit:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Controller
#Controller
public class EncuestaController {
#RequestMapping(value ="registrarEncuesta", method = RequestMethod.POST)
private String formularioEncuesta(#Valid #ModelAttribute("formEncuesta") EncuestaForm formEncuesta, BindingResult bindingResult,#RequestParam Map<String,String> allRequestParams)
{
if (bindingResult.hasErrors()) {
return "nuevaEncuesta";
}
try {
Encuesta nueva = formEncuesta.toEncuesta();
ServiceFactory.getEncuestaService().crearEncuesta(nueva,allRequestParams);
} catch (DataIntegrityViolationException e) {
return "nuevaEncuesta";
}
return "redirect:/encuestas";
}
}
You will have to read a little bit more about dependency injection. The central principle in Spring Framework is dependency injection which should be used to avoid referencing beans (service implementations, repository implementations etc...) statically. Spring container also servers as a bean factory that will instantiate and inject (autowire) implementations to beans that need them.
Because Spring will instantiate service interface implementations for you, you don't need ServiceFactory. In your controller you need to add a reference (a field) to EncuestaService and annotate it as Autowired and Spring will wire in the implementation. And then you can just use it in your controller.
#Controller
public class EncuestaController {
#Autowired
EncuestaService encuestaService;
#RequestMapping(value ="registrarEncuesta", method = RequestMethod.POST)
private String formularioEncuesta(#Valid #ModelAttribute("formEncuesta") EncuestaForm formEncuesta, BindingResult bindingResult,#RequestParam Map<String,String> allRequestParams)
{
if (bindingResult.hasErrors()) {
return "nuevaEncuesta";
}
try {
Encuesta nueva = formEncuesta.toEncuesta();
encuestaService.crearEncuesta(nueva,allRequestParams);
} catch (DataIntegrityViolationException e) {
return "nuevaEncuesta";
}
return "redirect:/encuestas";
}
}
I have the following class:
public static class ARestRequestParam
{
String name;
LocalDate date; // joda type
}
And I want it to be deserialized from the following JSON which is processed by jackson.
{ name:"abc", date:"20131217" }
Actually, I want to deserialize any LocalDate field in any class with "yyyyMMdd" format, without duplicating the format string, without adding any setter method, without any XML configuration. (That is, annotation and Java code is preferable)
How can it be done?
Also, I also want to know the serialization part. that is, LocalDate -> "yyyyMMdd".
I've seen followings:
jackson-datatype-joda (https://github.com/FasterXML/jackson-datatype-joda)
custom serializer (public class JodaDateTimeJsonSerializer extends JsonSerializer { ... } - Spring #ResponseBody Jackson JsonSerializer with JodaTime)
#JsonCreator
#DateTimeFormat
But I don't know which is applicable, and which is most up-to-date.
BTW, I use Spring Boot.
UPDATE
Ok, I have managed to write working code for the deserialization part.
It is as follows:
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
{
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters)
{
converters.add(jacksonConverter());
}
#Bean
public MappingJackson2HttpMessageConverter jacksonConverter()
{
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ApiJodaModule());
converter.setObjectMapper(mapper);
return converter;
}
#SuppressWarnings("serial")
private class ApiJodaModule extends SimpleModule
{
public ApiJodaModule()
{
addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
}
}
#SuppressWarnings("serial")
private static class ApiLocalDateDeserializer
extends StdScalarDeserializer<LocalDate>
{
private static DateTimeFormatter formatter =
DateTimeFormat.forPattern("yyyyMMdd");
public ApiLocalDateDeserializer() { super(LocalDate.class); }
#Override
public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
{
String s = jp.getText().trim();
if (s.length() == 0)
return null;
return LocalDate.parse(s, formatter);
}
throw ctxt.wrongTokenException(jp, JsonToken.NOT_AVAILABLE,
"expected JSON Array, String or Number");
}
}
}
I had to implement the deserializer myself, since the datetime format for the deserializer in jackson-datatype-joda cannot be altered. So, since I've implemented the deserializer myself, jackson-datatype-joda is not needed. (although I've copied pieces of its code)
Is this code Ok?
Is this up-to-date solution?
Is there any other easier way?
Any suggestion would be greatly appreciated.
UPDATE
Following Dave Syer's suggestion, I modified the source above as follows:
Removed 2 methods: configureMessageConverters(), jacksonConverter()
Added following method into WebMvcConfiguration class:
#Bean
public Module apiJodaModule()
{
return new ApiJodaModule();
}
But now it does not work. It seems apiJodaModule() is ignored.
How can I make it work?
(It seems that I should not have a class that has #EnableWebMvc to use that feature.)
The version I use is org.springframework.boot:spring-boot-starter-web:0.5.0.M6.
UPDATE
Final working version is as follows: (with other configurations I've done previously in the class that had #EnableWebMvc)
As Dave Syer mentioned, this will only work on BUILD-SNAPSHOT version, at least for now.
#Configuration
public class WebMvcConfiguration
{
#Bean
public WebMvcConfigurerAdapter apiWebMvcConfiguration()
{
return new ApiWebMvcConfiguration();
}
#Bean
public UserInterceptor userInterceptor()
{
return new UserInterceptor();
}
public class ApiWebMvcConfiguration extends WebMvcConfigurerAdapter
{
#Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(userInterceptor())
.addPathPatterns("/api/user/**");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/**")
.addResourceLocations("/")
.setCachePeriod(0);
}
}
#Bean
public Module apiJodaModule()
{
return new ApiJodaModule();
}
#SuppressWarnings("serial")
private static class ApiJodaModule extends SimpleModule
{
public ApiJodaModule()
{
addDeserializer(LocalDate.class, new ApiLocalDateDeserializer());
}
private static final class ApiLocalDateDeserializer
extends StdScalarDeserializer<LocalDate>
{
public ApiLocalDateDeserializer() { super(LocalDate.class); }
#Override
public LocalDate deserialize(JsonParser jp,
DeserializationContext ctxt)
throws IOException, JsonProcessingException
{
if (jp.getCurrentToken() == JsonToken.VALUE_STRING)
{
String s = jp.getText().trim();
if (s.length() == 0)
return null;
return LocalDate.parse(s, localDateFormatter);
}
throw ctxt.mappingException(LocalDate.class);
}
}
private static DateTimeFormatter localDateFormatter =
DateTimeFormat.forPattern("yyyyMMdd");
}
}
Your code is OK, but if you use #EnableWebMvc in a Spring Boot app you switch off the default settings in the framework, so maybe you should avoid that. Also, you now have only one HttpMessageConverter in your MVC handler adapter. If you use a snapshot of Spring Boot you ought to be able to simply define a #Bean of type Module and everything else would be automatic, so I would recommend doing it that way.
I am trying to learn TDD/BDD using NUnit and Moq.
The design that I have been following passes a DataService class to my controller to provide access to repositories.
I would like to Mock the DataService class to allow testing of the controllers.
There are lots of examples of mocking a repository passed to the controller but I can't work out how to mock a DataService class in this
scenerio.
Could someone please explain how to implement this?
Here's a sample of the relevant code:
[Test]
public void Can_View_A_Single_Page_Of_Lists()
{
var dataService = new Mock<DataService>();
var controller = new ListsController(dataService);
...
}
namespace Services
{
public class DataService
{
private readonly IKeyedRepository<int, FavList> FavListRepository;
private readonly IUnitOfWork unitOfWork;
public FavListService FavLists { get; private set; }
public DataService(IKeyedRepository<int, FavList> FavListRepository,
IUnitOfWork unitOfWork)
{
this.FavListRepository = FavListRepository;
this.unitOfWork = unitOfWork;
FavLists = new FavListService(FavListRepository);
}
public void Commit()
{
unitOfWork.Commit();
}
}
}
namespace MyListsWebsite.Controllers
{
public class ListsController : Controller
{
private readonly DataService dataService;
public ListsController(DataService dataService)
{
this.dataService = dataService;
}
public ActionResult Index()
{
var myLists = dataService.FavLists.All().ToList();
return View(myLists);
}
}
}
Create an interface like this:
public interface DataService
{
FavListService FavLists { get; }
void Commit();
}
Make your DataService implement this interface and your controller should depend on this interface. Problem solved :)
EDIT: This line of code:
dataService.FavLists.All().ToList();
is breaking the law of demeter and will be a pain to unit test your service. Create a method like AllFavList() on your service instead of all these chain of calls, it will be easier to mock.
EDIT2: How to mock you get property
dataService.SetupGet(d => d.FavLists).Returns(your_variable);