My current spring boot testing uses junit5 jupiter. I need to add in request bean.
Following discussion request scoped beans in spring testing, https://github.com/mariuszs/spring-test-web I was able to get it working using JUnit4.
#RunWith(SpringJUnit4ClassRunner.class) //Not OK to remove
#SpringBootTest
#Testcontainers
#ActiveProfiles("test")
public class MainControllerTest {
#Autowired
MyRequestBean myRequestBean;
#Test
public void requestScope() throws Exception {
System.out.println("myRequestBean..." + myRequestBean.getRandom());
}
}
#Component
#RequestScope
#Data
public class MyRequestBean {
int random;
#PostConstruct
public void started() {
random = new Random().nextInt();
System.out.println("Request bean created! random = " + random);
}
}
But myRequestBean is null if I remove
#RunWith(SpringJUnit4ClassRunner.class) I can't keep it since it breaks my current testing using Jupiter
How to get request scope bean testing work in jupiter?
Updated:
I setup a testing project to test above. It might have issue on bring up SpringBootTest. Everything works after I tested in my real project. Spring 5 supports request-scope bean testing.
Related
I am using Redis Server for message broker in my spring boot application.
Is there any simple way to Junit my publish and receive API?
e.g :
Publisher :
public String publish(Object domainObj) {
template.convertAndSend(topic.getTopic(), domainObj.toString());
return "Event Published";
}
Receiver :
public class Receiver implements MessageListener {
#Override
public void onMessage(Message message, byte[] bytes) {
System.out.println("Consumed Message {}" + message);
}
}
I am using JedisConnectionFactory and RedisMessageListenerContainer and RedisTemplate for my implementation
#Configuration
#EnableRedisRepositories
public class RedisConfig {
#Bean
public JedisConnectionFactory connectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName("localhost");
configuration.setPort(6379);
return new JedisConnectionFactory(configuration);
}
#Bean
public RedisTemplate<String, Object> template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new JdkSerializationRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
#Bean
public ChannelTopic topic() {
return new ChannelTopic("common-channel");
}
#Bean
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(new Receiver());
}
#Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.addMessageListener(messageListenerAdapter(), topic());
return container;
}
Unit Testing Receiver and Publisher implementation is quite straight.
JUnit 5 coupled with Mockito extension should do the job.
For example for testing that :
public String publish(Object domainObj) {
template.convertAndSend(topic.getTopic(), domainObj.toString());
return "Event Published";
}
I expect that topic and template be fields of the current class.
These fields could be set by constructor.
So you could write something that check that convertAndSend() is eventually executed with the correct parameters :
#Mock
RedisTemplate<String, Object> templateMock;
#Test
void publish(){
Topic topicFixture = new Topic(...);
Object domainObjFixture = new FooBar(...);
Publisher publisher = new Publisher(templateMock, topicFixture);
//when
publisher.publish(domainObjFixture);
// then
Mockito.verify(templateMock)
.convertAndSend(topicFixture.getTopic(), domainObjFixture);
}
But I don't think that the unit test of these two classes be enough because it never tests the final things : the JMS processing performed by Redis backend.
Particularly, the RedisConfig part that you set with specific things as serializers that have important side effects on the processing.
For my part, I try to always write integration or partial integration tests for Redis backend stuffs to ensure a good no regression harness.
The java embedded-redis library is good for that. It allows to start a redis server
on localhost (works on Windows as well as on Linux).
Starting and stopping the redis server is as simple as :
RedisServer redisServer = new RedisServer(6379);
redisServer.start();
// do some work
redisServer.stop();
Move the start() in the #BeforeEach and the stop() in the #AfterEach and the server is ready.
Then it still requires some adjustments to ensure that the redis configuration specified in Spring is well setup during the tests while using your local redis server and not the "real" redis server. Not always simple to set but great when it is done !
The simplest way to unit test this is to use embedded-redis module. What you do is in BeforeAll you can start embedded Redis and stop the embedded Redis in AfterAll method.
You can also PostConstruct PreDestroy annotations to accomplish this.
If you're looking for Junit5 then you can find the code in my repo here
See BootstrapRedis annotation and their usage here
https://github.com/sonus21/rqueue/blob/7ef545c15985ef91ba719f070f7cc80745525047/rqueue-core/src/test/java/com/github/sonus21/rqueue/core/RedisScriptFactoryTest.java#L40
I am writing unit test for the below code using junit and mockito
public class Abc implements Runnable
{
private static ServerSocket server;
private static int port;
public Abc(int cPort)
{
port = cPort;
}
public void run()
{
init();
}
public static void init()
{
try {
server = new ServerSocket(port);
...something...
client.close();
}
}
catch(IOException e)
{
System.out.println("Exception inside init()...");
e.printStackTrace();
}
}
};
Unit test I have written
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServerSocket.class})
public class abcTest {
#Mock (name = "server") //same name as private var.
ServerSocket mockServer;
#InjectMocks
Abc abc;
#Test
public void testInit() throws Exception {
int port = 1880;
Socket mockClient = Mockito.mock(Socket.class);
PowerMockito.whenNew(ServerSocket.class).
withArguments(anyInt()).thenReturn(mockServer);
abc = new Abc(port);
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
};
But the call always go to original function definition. I am using junit 4.11 with mockito 2.28.2 and powermockito 2.0.2. I'm using java after a long time. Now its feel like kind of new. Please correct me if anything wrong in the code also.
You will need to change your PrepareForTest annotation
to #PrepareForTest({Abc.class}).
From the PowerMockito docu:
This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated
In this case that refers to the class which creates the new instance of ServerSocket. ServerSocket itself is a non-final public class that does not require special handling from PowerMockito (instead Mockito can deal with this class on its own).
You could also change your test to do the following:
#Test
public void testInit() throws Exception {
int port = 1880;
ServerSocket mockServer = Mockito.mock(ServerSocket.class);
PowerMockito.whenNew(ServerSocket.class)
.withArguments(Mockito.anyInt()).thenReturn(mockServer);
Abc.port = port;
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
(This first point is unrelated to whether the test fails or succeeds)
I do not know why you mix object's and static method behaviour together, but I think you should change that.In the test instead of creatic an ABC object, just could just set the static port variable directly.
Or alternatively change the whole ABC class into an object.
#InjectMocks failed for me as there is no default constructor
(Actually I got an error message in the console when trying to execute your code)
Additonaly you create a new instance of ABC in your test, which would have overwritten the things done by the annotations. Also as server is created during the init call, there is no need to inject a mock for it.
powermockito 2.0.2 actually depends on junit 4.12, so I am not sure what effects downgrading to an older version might have.
Socket mockClient seemed somewhat unrelated to the code your posted, so I removed it from my example in the answer, however as you use a client (I assume that is your Socket) in your code your probably need to do some mocking for that as well and provide the mock to the method accordingly.
I'm using Springboot2, Spring5 and reactive-webflux in my Java microservices.
I have a service class which I want to test using webtestclient:-
#Service("authenticationProvider")
public class CommonAuthenticationProvider implements AuthenticationProvider {
#Override
public AccessToken getUserAccessToken(Tuple2<String, WebClient> serviceConnectionDetails, MultiValueMap<String, String> queryParams) {
return serviceConnectionDetails._2
.post()
.uri(builder -> builder
.path(serviceConnectionDetails._1)
.queryParams(queryParams)
.build())
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
.retrieve()
.bodyToMono(AccessToken.class)
.block();
}
}
Here serviceConnectionDetails._2 is a webclient instance. I want to write a JUnit test to mock this webclient and test the method getUserAccessToken(). Please assist as I had tried many things like mockmvc, mockRestServiceServer but nothing worked. Later I came to know that, I cannot user mockRestServiceServer since it used to mock RestTemplate and not WebClient. I can test controller class methods using webtestclient but not this at service class
This should be supported in a future Spring Framework version with MockRestServiceServer; see SPR-15286.
For now, the only solution is to use a separate library for that, such as okhttp's MockWebServer.
Trying to test a gateway in spring integration using mockito but when autowiring the gateway its always null.
I am using annotations to create a context for writing the test case, but the mockito and annotations are all working weird.
Getting no support or basic understanding that what is going wrong here.
Can anyone please suggest a simple way or how to test a spring integration flow, which starts with a gateway. As the value for the gateway is coming null for me in the test.
we are using java annotations to define the spring integration flow like below :
public class integrationFlow()
{
#MessagingGateway
public interface EnterHere{
#Gateway(requestChannel = "requestChannel")
void process(DtoObject dtoObject)
}
#Bean
public IntegrationFlow myFlow() {
return IntegrationFlows.from(requestChannel)
.filter()
//... its a big flow with lot of interactions
.get();
}
}
I have written a test case that will create an object with default values that will be passed to the dto and that will trigger the flow of spring integration.
i want to use mockito here as there are lots of dependencies in the project.
i am using
#Autowired
private EnterHere enterhere
and in contextconfguration for the test case i am defining
#MessagingGateway
public interface EnterHere{
#Gateway(requestChannel = "requestChannel")
void process(DtoObject dtoObject)
}
But when in the test case
#Test
public void testGateway(){
enterHere.process(this.dtoObjectMock)
// i am always getting a null value at this enterhere.
}
We are not using Spring boot , we are using Mockito annotations, #Mock and #InjectMocks ,#Runwith(MockitoJunit4Runner.class) like these
I have a listener test, where i post a message in a parallel thread and check with LatchCountDownAndCallRealMethodAnswer if the all were processed successfully. Running the test alone, it works perfectly, however if you run all other tests together, it fails because it failed to leave the counter at zero, but the listener received and processed the message normally. Does anyone have any ideas?
My Test Class
#RunWith(SpringRunner.class)
#SpringBootTest
#RabbitListenerTest
#ActiveProfiles("test")
public class EventListenerTest {
EventListener eventListener;
#Autowired
protected RabbitListenerTestHarness harness;
#Autowired
private EventStoreRepository repository;
#SpyBean
private DomainEventPublisher publisher;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
DomainRegister.setDomainEventPublisher(publisher);
eventListener = this.harness.getSpy("eventListenerId");
}
#Test
public void storeEventsListenerTest() throws Exception {
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
doAnswer(answer).when(eventListener).storeEvents(any(BalanceReserved.class));
publisher.publish(new BalanceReserved("12233", 150.0, BigDecimal.ZERO), "");
assertTrue(answer.getLatch().await(10, TimeUnit.SECONDS));
verify(eventListener, times(1)).storeEvents(any(BalanceReserved.class));
}
#After
public void tearDown() {
DomainRegister.setDomainEventPublisher(null);
reset(eventListener);
repository.deleteAll();
}
}
Error
java.lang.AssertionError
If you have other tests using the same queue, you need to shut down the application context for each test so the test's listeners are stopped. By default, the Spring Test framework caches the application context for reuse. This will cause other tests to "steal" messages.
Add #DirtiesContext to each test class that uses #RabbitListeners, to tell the test framework to shutdown the context.