Regarding Spring's #Autowired and Wicket's #SpringBean - spring

I am currently looking into integrating Mockito and JUnit into my Wicket/Spring/Hibernate project and have found a tutorial on how to do this using annotations.
Trouble is I am unfamiliar with #Autowired and after a look on google I am finding it hard to see the difference between this annotation and the #SpringBean annotation.
Are they one in the same or is there a difference I should be aware of ?
My code to offer some context to this question:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
#TransactionConfiguration(transactionManager = "txManager", defaultRollback = false)
public class TestHome
{
private WicketTester tester;
#Autowired
private ApplicationContext ctx;
#Autowired
private WebApplication webApplication;
#Before
public void setUp() {
tester = new WicketTester(webApplication);
}
#Test
#Transactional
#Rollback(true)
public void testRenderHomePage() {
tester.startPage(Home.class);
tester.assertRenderedPage(Home.class);
tester.assertComponent("home", Home.class);
}
}

If you use Wicket SpringComponentInjector, it uses its own injection. The #Autowired annotation is a Springframework annotation, but Wicket SpringComponentInjector ignores that. So the Wicket annotation is #SpringBean that marks a field to be autowired (injected) by Spring bean or component that has to exist in Spring context.
In you code snippet you use the SpringJUnit4ClassRunner runner, so your fields are injected by Spring, so it is correct.
See an example, how to use SpringComponentInjector at How can I get a Spring bean injected in my custom Wicket model class?

Related

PostConstruct and test

I use spring boot 3
Main spring boot class
#EnableTransactionManagement
#SpringBootApplication
#Slf4j
public class FlexApplication{
private final ApplicationParameterManager appParamManager;
public FlexApplication(ApplicationParameterManager appParamManager) {
this.appParamManager = appParamManager;
}
#PostConstruct
public void init(){
}
....
}
#Service
#Slf4j
public class ApplicationParameterManager{
....
}
Basic test
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
#DataJpaTest
public class ListUserRepositoryTest {
#Autowired
private ListUserRepository repository;
#Test
public void getListUserByUserType(){
String typeUser = "CETEST";
Pageable page = Pageable.ofSize(10);
Page<ListUser> pageListUser = repository.findAllByTypeUser(typeUser, page);
assertThat(pageListUser.getContent().size() > 5 ).isTrue();
}
}
Otherwise this test, application run well
I get this error
Parameter 0 of constructor in com.acme.FlexApplication required a bean
of type 'com.acme.parameter.ApplicationParameterManager' that could
not be found.
I think it is not related to version of Spring Boot.
As you're using #DataJpaTest , your bean is not created
Spring Docs:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
Solution would be to use #SpringBootTest instead of #DataJpaTest if your test is not really a JPA test.
Also, still using #DataJpaTest you could add #Import(ApplicationParameterManager.class) to your test class
When using #DataJpaTest, you are not creating the whole spring context as when you run the application normally but you only create the beans responsible for data access layer.
In order to run your tests properly, you need to provide a mocked bean of type ApplicationParameterManager.
The easiest way to do it is by utilizing #MockBean annotation.
So, to make your tests work, edit the test in the following way.
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
#DataJpaTest
public class ListUserRepositoryTest {
#MockBean
private ApplicationParameterManager applicationParameterManager;
#Autowired
private ListUserRepository repository;
#Test
public void getListUserByUserType(){
String typeUser = "CETEST";
Pageable page = Pageable.ofSize(10);
Page<ListUser> pageListUser = repository.findAllByTypeUser(typeUser, page);
assertThat(pageListUser.getContent().size() > 5 ).isTrue();
}
}
That way, the spring context will include a mocked bean of your required dependency.
Take a look at #MockBean java doc for more information. https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html
If you prefer to run the whole spring context in order to perform full integration tests, take a look at #SpringBootTest annotation.
#DataJpaTest should be used when you want to test data access layer in isolation.

Write Unit test in SpringBoot Without start application

Am developing MicroServices in springBoot. Am writing unit test for Service and DAO layer. When I use #SpringBootTest it starting application on build. But It should not start application
when I run unit test. I used #RunWith(SpringRunner.class), But am unable to #Autowired class instance in junit class. How can I configure junit test class that should not start application and how to #Autowired class instance in junit class.
Use MockitoJUnitRunner for JUnit5 testing if you don't want to start complete application.
Any Service, Repository and Interface can be mocked by #Mock annotation.
#InjectMocks is used over the object of Class that needs to be tested.
Here's an example to this.
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
public class AServiceTest {
#InjectMocks
AService aService;
#Mock
ARepository aRepository;
#Mock
UserService userService;
#Before
public void setUp() {
// MockitoAnnotations.initMocks(this);
// anything needs to be done before each test.
}
#Test
public void loginTest() {
Mockito.when(aRepository.findByUsername(ArgumentMatchers.anyString())).thenReturn(Optional.empty());
String result = aService.login("test");
assertEquals("false", result);
}
With Spring Boot you can start a sliced version of your application for your tests. This will create a Spring Context that only contains a subset of your beans that are relevant e.g. only for your web layer (controllers, filters, converters, etc.): #WebMvcTest.
There is a similar annotation that can help you test your DAOs as it only populates JPA and database relevant beans (e.g. EntitiyManager, Datasource, etc.): #DataJpaTest.
If you want to autowire a bean that is not part of the Spring Test Context that gets created by the annotatiosn above, you can use a #TestConfiguration to manually add any beans you like to the test context
#WebMvcTest(PublicController.class)
class PublicControllerTest {
#Autowired
private MockMvc mockMvc;
#TestConfiguration
static class TestConfig {
#Bean
public EntityManager entityManager() {
return mock(EntityManager.class);
}
#Bean
public MeterRegistry meterRegistry() {
return new SimpleMeterRegistry();
}
}
}
Depending your test setup, if you don't want to autowire a mock but the "real thing", You could simply annotate your test class to include exactly the classes you need (plus their transitive dependencies if necessary)
For example :
#SpringJUnitConfig({ SimpleMeterRegistry.class })
or
#SpringJUnitConfig
#Import({ SimpleMeterRegistry.class })
or
#SpringJUnitConfig
#ContextConfiguration(classes = { SimpleMeterRegistry.class })
See working JUnit5 based samples in here Spring Boot Web Data JDBC allin .

not able to replace spring bean with mock in camel route

using #Profile I am able to mock the spring bean, however in the camel route which mock bean method is not invoked. I am using SpringJUnit4ClassRunner.class and using #ActiveProfile
Below is the route in which I want to replace, cancelSubscriptionTransformer, myBeanClient, extendedClient beans with my mock beans in unit testing.
from("{{cancelSubscriptionFromRMQUri}}").routeId("cancelSubscriptionRoute")
.unmarshal().json(JsonLibrary.Jackson, Subscription.class)
.bean("cancelSubscriptionTransformer", "toKbCancelSubscription")
.choice()
.when().simple("${body.serviceType} == 'subscriptions'")
.bean("myBeanClient", "cancelSubscription(${body.subscriptionId}, ${body.createdBy}, ${body.reason}, ${body.comment})")
.bean("extendedClient", "retrieveSubscription(${body.subscriptionId}, ${body.externalKey})")
.marshal(json)
.to("{{cancelSubscriptionTORMQUri}}")
.when().simple("${body.serviceType} == 'usage'")
.bean("myBeanClient", "cancelSubscription(${body.subscriptionId}, ${body.dateTime},null, null, -1, ${body.createdBy}, ${body.reason}," +
" ${body.comment})")
.endChoice();
Below is how I define my ExtendedClientMock, I use the same approach for the rest of the mock beans
#Profile("test")
#Primary
#Repository
public class ExtendedClientMock extends ExtendedClient {
public Subscription retrieveSubscription(UUID subscriptionid, String sdpSubscriptionId) throws MyClientException {
Subscription subs=new Subscription();
subs.setProductName("test");
return subs;
}
}
Below is the code for unit testing:
#ActiveProfiles({"test", "aop"})
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = CancelSubscriptionRouteTest.class)
#EnableAutoConfiguration
#ComponentScan
#ContextConfiguration(classes = { BillingServicesApplication.class })
#UseAdviceWith
public class CancelSubscriptionRouteTest {
#Autowired
protected CamelContext camelContext;
#Autowired
private CancelSubscriptionTransformer cancelSubscriptionTransformer;
#Autowired
private ExtendedClient extendedClient;
#Autowired
private MyBeanClient myBeanClient;
#EndpointInject(uri = "{{cancelSubscriptionTORMQUri}}")
private MockEndpoint cancelSubscriptionTORMQUriEndpoint;
#EndpointInject(uri = "{{cancelSubscriptionFromRMQUri}}")
private ProducerTemplate cancelSubscriptionFromRMQUriEndpoint;
#Inject
private ObjectMapperContextResolver objectMapperContextResolver;
#Test
#DirtiesContext
public void testCancelSubscriptionRoute() throws Exception {
cancelSubscriptionTORMQUriEndpoint.expectedMessageCount(1);
ObjectMapper objectMapper= objectMapperContextResolver.getContext(ObjectMapperContextResolver.class);
String jsonString=objectMapper.writeValueAsString(subscription);
CancelSubscription cancelSubscription=cancelSubscriptionTransformer.toKbCancelSubscription(subscription);
Assert.assertEquals("mock auto created by amel",cancelSubscription.getComment());
cancelSubscriptionFromRMQUriEndpoint.sendBody(" {{cancelSubscriptionFromRMQUri}}",jsonString);
cancelSubscriptionTORMQUriEndpoint.assertIsSatisfied();
}
}
The Assert.assertEquals("mock auto created by amel",cancelSubscription.getComment()); gets statisfied by calling cancelSubscriptionTransformer.toKbCancelSubscription which is invoked on the mock bean. however when message is sent to cancelSubscriptionFromRMQUriEndpoint.sendBody, the route is invoked and the actual beans in the route are not being replaced by mock beans
#MickaƫlB looks like the issue was I was not extending the correct bean and also I had to use #Inject in my route builder spring bean and use bean name instead of string format of bean name
This is very old but I ran into this issue.
The answer is that instead of .Bean(MyBean.class, "myMethod"), you should use .to("bean:myBean?method=myMethod"). The reason is that the first way, Camel will instantiate the bean. The 2nd way, Spring has control of the bean and camel will look it up. Therefore you can use Spring mockBean to change it.
I'm using Camel version 3 now by the way, and beanRef is removed. If you used beanRef, replace it with .to("bean:myBean?method=myMethod).

setting mocked object in case of spring annotation

I'm writing unit test case using Junit, EasyMock and Spring. I'm trying to mock DAO layer call. I've used annotation to inject bean in my application
Service layer class:
public class CustomerService {
#Autowired
private CustomerDao customerDao;
........
public void findCustomerByAccountNumber(String accountNumber){
}
}
Test case for service method:
public class CustomerServiceTest extends AbstractContextConfigLoaderTest{
private CustomerDao mockCustomerDao;
private CustomerService customerService;
private String accountNumber="5247710009575432";
#Before
public void setUp(){
mockCustomerDao= EasyMock.createMock(CustomerDao.class);
customerService= new CustomerService();
}
if i would have used setter injection using Spring bean configuration, i would've set mocked dao object to customerService like below.
customerService.setCustomerDao(mockCustomerDao);
How can i do the same in case of Spring annotation ?
You can use still setup a method
protected void setCustomerDao(CustomerDao customerDao)
and only use it in your JUnit to set the mocked dependencies. The protected access will prevent any class that is not in the same package from using that method.
I suggest enabling spring in your test with something like #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration, in your spring context for the test
make the mock as spring bean.
<bean class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="some.package.CustomerDao" />
</bean>
Now should be wired to the CustomerService, to record the expected behavior you will need to wire the mock in your test class:
#Autowired
private CustomerDao mockCustomerDao;
#Autowired
private CustomerService customerService;
Why not expose this through the constructor and inject it that way? Your production code can use Spring and your test code can just instantiate the object directly.
At the moment you're at the mercy of your DI framework. Break that dependency.

#ManagedProperty equivalent in Spring

I am using Spring for my DI.
Is there an equivalent of #ManagedProperty? I want to inject the value from one view scoped bean into another one on the next page.
e.g
#Component
#Scope("view")
public class Page1Bean(){
private String value;
}
#Component
#Scope("view")
public class Page2Bean(){
#ManagedProperty(value = #{page1Bean}") //doesnt work in Spring
private Page1Bean bean;
}
#Resource or #Autowired should work. #Resource is the Java EE implementation, #Autowired is the spring specific annotation. I can't find the reference now, but it seems like I read once to prefer #Resource over #Autowired.
here's a blog post I found that talks about #Inject vs. #Resource vs. #Autowired
http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/#more-2350

Resources