How can i make DateUtil throw an exception? - java

#Override
public void contextDestroyed(ServletContextEvent sce) {
try{
DateUtil.clean();
}catch(Exception e){
LOGGER.error("MyServletContextListener contextDestroyed error: ", e);
}
I am doing unit testing on the above piece of code, and am trying to get 100% line coverage by hitting the Exception clause, however, i cant seem to make it work with my implementation. Would appreciate any help yall. Please look below for my implementation.
#Test (expected= Exception.class)
public void test_contextDestroyed_Exception() {
DateUtil wrapper = Mockito.spy(new DateUtil());
Exception e = mock(Exception.class);
when(wrapper).thenThrow(e);
Mockito.doThrow(e)
.when(myServletContextListener)
.contextDestroyed(sce);
myServletContextListener.contextDestroyed(sce);
}

Since DateUtil.clean() is a static method, you can't mock it with Mockito.
You need to use PowerMockito instead:
<properties>
<powermock.version>1.6.6</powermock.version>
</properties>
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Check official PowerMock documentation for version compatibility with JUnit and Mockito.
Once you did that, you should add the following to your test class:
#RunWith(PowerMockRunner.class) //<-- this says to JUnit to use power mock runner
#PrepareForTest(DateUtil.class) //<-- this prepares the static class for mock
public class YourTestClass {
#Test(expected = Exception.class)
public void test_contextDestroyed_Exception() {
PowerMockito.mockStatic(DateUtil.class);
when(DateUtil.clean()).thenThrow(new Exception("whatever you want"));
//prepare your test
//run your test:
myServletContextListener.contextDestroyed(sce);
}
}

you can use mockito-inline artifact from Mockito to test static methods and follow the below approach,
try (MockedStatic<DateUtil> utilities = Mockito.mockStatic(DateUtil.class)) {
utilities.when(DateUtil::clean).thenThrow(Exception.class);
// assert exception here
}
for more info,
https://frontbackend.com/java/how-to-mock-static-methods-with-mockito

Related

NPE Testing Kafka Producer Using Embedded Kafka

I've written a basic spring boot service that consumes some data via rest API and publishes it to rabbitmq and kafka.
To test the service class handling kafka producing, I followed this guide: https://www.baeldung.com/spring-boot-kafka-testing
In isolation, the test (KafkaMessagingServiceImplTest) works perfectly both in intellij idea and via mvn on the command line. Running all project tests in idea works fine. However, when I run all project tests via maven on the command line, this test fails with an NPE when trying to make the assertion on the payload String.
I've narrowed down the location of the root problem to another test class (AppPropertiesTest) which is solely testing my AppProperties component (which is a component I use to pull config from application.properties in a tidy way). When, and only when, the tests within that test class are run alongside the failing test using 'mvn clean install' in project root, does the NPE show up. Commenting out the tests in this class or annotating it with #DirtiesContext fixes the problem. Apparently something loaded into the spring context by this test class causes an issue with the timing/order of events/countdownlatch in the other test. Of course, I don't want to use #DirtiesContext as it can lead to a much slower build as the project increases in complexity. It also does not explain the problem.. and I can't handle that :)
AppPropertiesTest uses constructor injection to inject the AppProperties component. It also extends a abstract class 'GenericServiceTest' which is annotated by:
#SpringBootTest
#TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
and contains nothing else. As you probably know, the SpringBootTest annotation builds a test spring context and wires in boilerplate to allow effective testing of a spring app's dependency injection etc. and the TestConstructor annotation allows constructor injection in some of my tests. FWIW, I have tried removing the TestConstructor annotation and using plain old Autowiring in the AppProperties class to see if it makes a difference but it does not.
The failing test class also extends GenericServiceTest, as it requires the spring context to inject some of the dependencies such as the consumer and the messaging service being tested and AppProperties instance within etc.
So I know where the problem lies but I don't know what the problem is. Even when the test fails with the NPE, I can see in the logs that the consumer has successfully consumed the message before the failure, as per the Baeldung guide :
TestKafkaConsumer : received payload='ConsumerRecord(topic = test-kafka-topic, partition = 0, leaderEpoch = 0, offset = 0, CreateTime = 1618997289238, serialized key size = -1, serialized value size = 43, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = This is a test message to be sent to Kafka.)'
However, the payLoad is null when we get back to the assertion. I've tried all kinds of things like Thread.sleep() in the failing test to give it more time and I've increased the await() timeout but no joy.
I find it bizarre that the tests are fine in IDEA and in isolation. Now it's starting to drive me a little crazy and I can't debug it because the problem doesn't occur in my IDE.
If anyone has any ideas, it would be greatly appreciated!
Thanks.
EDIT: Someone very reasonably suggested that I add some code so here goes :)
The Failing Test (fails at assertTrue(payload.contains(testMessage)) because payLoad is null). The autowired kafkaMessagingService simply has the dependencies of AppProperties and KakfaTemplate injected and calls kafkaTemplate.send():
#EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" })
class KafkaMessagingServiceImplTest extends GenericServiceTest {
#Autowired
#Qualifier("kafkaMessagingServiceImpl")
private IMessagingService messagingService;
#Autowired
private TestKafkaConsumer kafkaConsumer;
#Value("${app.topicName}")
private String testTopic;
#Test
public void testSendAndConsumeKafkaMessage() throws InterruptedException {
String testMessage = "This is a test message to be sent to Kafka.";
messagingService.sendMessage(testMessage);
kafkaConsumer.getLatch().await(2000, TimeUnit.MILLISECONDS);
String payload = kafkaConsumer.getPayload();
assertTrue(payload.contains(testMessage));
}
The TestConsumer (used to consume in the test above)
#Component
public class TestKafkaConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(TestKafkaConsumer.class);
private CountDownLatch latch = new CountDownLatch(1);
private String payload = null;
#KafkaListener(topics = "${app.topicName}")
public void receive(ConsumerRecord<?, ?> consumerRecord) {
LOGGER.info("received payload='{}'", consumerRecord.toString());
setPayload(consumerRecord.toString());
latch.countDown();
}
public CountDownLatch getLatch() {
return latch;
}
public String getPayload() {
return payload;
}
public void setPayload(String payload) {
this.payload = payload;
}
Project dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.5.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka-test -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<version>2.5.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
AppPropertiesTest class (the context of which seems to cause the problem)
class AppPropertiesTest extends GenericServiceTest {
private final AppProperties appProperties;
public AppPropertiesTest(AppProperties appProperties) {
this.appProperties = appProperties;
}
#Test
public void testAppPropertiesGetQueueName() {
String expected = "test-queue";
String result = appProperties.getRabbitMQQueueName();
assertEquals(expected, result);
}
#Test
public void testAppPropertiesGetDurableQueue() {
boolean isDurableQueue = appProperties.isDurableQueue();
assertTrue(isDurableQueue);
}
}
The AppProperties class that the AppPropertiesTest class is testing:
#Component
#ConfigurationProperties("app")
public class AppProperties {
// a whole bunch of properties by name that are prefixed by app. in the application.properties file. Nothing else
}
The Generic service test class which both tests extend.
#SpringBootTest
#TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public abstract class GenericServiceTest {
}
The failure (you can see on the line above the payload has been received and printed out).
2021-04-21 14:15:07.113 INFO 493384 --- [ntainer#0-0-C-1] service.TestKafkaConsumer : received payload='ConsumerRecord(topic = test-kafka-topic, partition = 0, leaderEpoch = 0, offset = 0, CreateTime = 1619010907076, serialized key size = -1, serialized value size = 43, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = This is a test message to be sent to Kafka.)'
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.791 s <<< FAILURE! - in
service.KafkaMessagingServiceImplTest
[ERROR] testSendAndConsumeKafkaMessage Time elapsed: 2.044 s <<< ERROR!
java.lang.NullPointerException
at service.KafkaMessagingServiceImplTest.testSendAndConsumeKafkaMessage(KafkaMessagingServiceImplTest.java:42)
The problem is that TestListener is a #Component so it is being added twice - the record is going to the other instance.
I added more debugging to verify the getter is called on a different instance.
#Component
public class TestKafkaConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(TestKafkaConsumer.class);
private final CountDownLatch latch = new CountDownLatch(1);
private String payload = null;
#KafkaListener(id = "myListener", topics = "${app.kafkaTopicName}")
public void receive(ConsumerRecord<?, ?> consumerRecord) {
LOGGER.info("received payload='{}'", consumerRecord.toString());
setPayload(consumerRecord.toString());
if (payload != null) {
LOGGER.info(this + ": payload is not null still");
}
latch.countDown();
if (payload != null) {
LOGGER.info(this + ": payload is not null after latch countdown");
}
}
public CountDownLatch getLatch() {
return latch;
}
public String getPayload() {
LOGGER.info(this + ": getting Payload");
return payload;
}
public void setPayload(String payload) {
this.payload = payload;
}
}
If you don't want to use #DirtiesContext, you can at least stop the listener containers after the tests complete:
#SpringBootTest
#TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public abstract class GenericDataServiceTest {
#AfterAll
static void stopContainers(#Autowired KafkaListenerEndpointRegistry registry) {
registry.stop();
}
}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

How to write assertTimeoutPreemptively (JUnit 5) in JUnit 4?

Till now I was working on JUnit 5 and now I have to work on an old system with JUnit 4 and I cannot update JUnit 5 there. I have a test in JUnit 5 that I have to write in JUnit 4 but I am not sure how it will work or how to write? Below is the JUnit 5 version of the test.
#AfterEach
void afterEach() throws Exception {
// Bleed off any events that were generated...
assertTimeoutPreemptively(ofMillis(MESSAGE_CLEARING_TIMEOUT_MS), () -> {
boolean tryAgain = true;
while (tryAgain) {
try {
final IMessageFacade message = messageConsumer.receiveMessage(MESSAGE_TIMEOUT_MS);
message.acknowledge();
} catch (MessagingException e) {
tryAgain = false;
}
}
});
broker.stop();
}
In the test, I am using assertTimeoutPreemptively() and am not sure how to convert it to JUnit 4. I tried putting a timeout which is a global timeout in JUnit 4 but that didn't work. Any guidance in terms of writing above #AfterEach condition with JUnit 4?
Shouldn't assertions run only once? Finding asserts in test teardown is somehow surprising. Consider to make your assertions part of your tests.
In JUnit 5 this looks like:
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
public class TimeoutJUnit5Test {
#Test #Timeout(value = 10, unit = MILLISECONDS)
void junitFiveTimeout() {
// ...
}
}
and in JUnit 4:
import org.junit.Test;
public class TimeoutJUnit4Test {
#Test(timeout = 10)
public void junitFourTimeout() {
// ...
}
}
What's stopping you from using both versions of JUnit? (pom.xml):
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
Last option would be to simply copy / adapt the behaviour from the new JUnit 5 assertTimeoutPreemptively() to you own project.

How do I perform BDD test for spring application when am running the the front end using another framework (vuejs) which is running on different port

Am trying to perform BDD tests for my spring application. Am using vuejs for the front end which runs on different port.
My problem is that spring application is failing to connect to the front end application(returns 404 status)
Here is the code on how am connecting to the front end.
import static org.assertj.core.api.Assertions.assertThat;
#ContextConfiguration(classes = MainApplication.class)
#WebAppConfiguration
public class PlantRequestSteps {
List<Plant> plants = new ArrayList<>();
#Autowired
private WebApplicationContext wac;
private WebClient customerBrowser;
HtmlPage customerPage;
#Autowired
PlantHireRepository plantHireRepository;
#Before
public void setUp() {
customerBrowser = MockMvcWebClientBuilder.webAppContextSetup(wac).build();
}
#After
public void tearOff() {
plantHireRepository.deleteAll();
plants.clear();
}
#Given("^the following plants are vailable from this given date$")
public void the_following_plants_are_vailable_from_this_given_date(DataTable table){
for (Map<String, String> row: table.asMaps(String.class, String.class)){
plants.add(Plant.of(
Long.parseLong(row.get("id")), row.get("name"),
row.get("description"), new BigDecimal(row.get("price")),
LocalDate.parse(row.get("date"))));
}
}
#Given("^am on BuildIT's \"([^\"]*)\" web page$")
public void am_on_BuildIT_s_web_page(String arg1) throws Throwable {
customerPage = customerBrowser.getPage("http://localhost:8081/");
}
}
I managed to solve my problem by changing the testing library. Previously I was using HtmlUnit which only works when both the front end and back end are running on the same port(coupled together).
I used selenium and chrome driver which are independent of spring framework
Here is a basic setup ... .....
public class PlantRequestSteps {
#Autowired
private WebApplicationContext wac;
private WebDriver driver ;;
static {
// you should specify the path where you installed your chrome driver
// as the second parameter to this function
System.setProperty("webdriver.chrome.driver", "/path/chromedriver");
}
#Before
public void setup() {
driver = new ChromeDriver();
}
#After
public void tearoff() {
driver.close();
}
#Given("^ that am on this \"([^\"]*)\" web page$")
public void that_am_on_this_web_page(String arg1) throws Throwable {
driver.get("http://localhost:8081/");
}
Also do not forget to add the selenium library in addition to Junit library . Am using maveen so I added mine in the pom.xml file.
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.1</version>
<scope>test</scope>
</dependency>
Finally make sure you have the latest version of chrome driver installed(the old version seems not work )

Mockito.spy VerifyError: Constructor must call super() or this()

I am trying to execute simple test case, but getting an error. Below is my test case :
#Rule
public AemContext context = new AemContext();
#Test
public void test() throws Exception {
Resource currentResource = context
.create()
.resource("/content/app/en-us/page", "jcr:title", "Title Page", "width", "5","height","9");
inheritanceValueMap = Mockito.spy(new HierarchyNodeInheritanceValueMap(currentResource));
Assert.assertThat(inheritanceValueMap.getInherited("width", StringUtils.EMPTY), Is.is("5"));
}
Error I am getting is :
java.lang.VerifyError: (class: com/day/cq/commons/ValueMapWrapper, method: signature: (Lorg/apache/sling/api/resource/ValueMap;)V) Constructor must call super() or this()
Any solution to this?
This issue usually comes when we use below dependency of uber jar :
<dependency>
<groupId>com.adobe.aem</groupId>
<artifactId>uber-jar</artifactId>
<version>6.2.0</version>
<classifier>obfuscated-apis</classifier>
<scope>provided</scope>
</dependency>
Try changing the dependency classifier to apis , as shown below:
<dependency>
<groupId>com.adobe.aem</groupId>
<artifactId>uber-jar</artifactId>
<version>6.2.0</version>
<classifier>apis</classifier>
<scope>provided</scope>
</dependency>

How to test static method invokation in Android?

I have an Android activity and I want to write a unit test, which verifies that in onResume the activity checks whether the Internet is available.
public class MyActivity {
#Override
protected void onResume() {
super.onResume();
setContentView(R.layout.connect_to_server);
// Internet availability check
final IInternetAvailabilityChecker checker = InternetAvailabilityChecker.create(this);
if (!checker.isInternetAvailable())
{
Utils.showMessageBox(this, R.string.app_name,
R.string.internet_not_available);
return;
}
In the test, I want to verify that MyActiviy.onResume calls the InternetAvailabilityChecker.create method.
How can I do it (with any free mocking framework compatible with Android) ?
I tried to use PowerMock for this (see example below), but when I try to run the test, I get errors like MockTest.java:7: package org.powermock.core.classloader.annotations does not exist.
Maven:
<properties>
<powermock.version>1.5.1</powermock.version>
</properties>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
Unit test:
#RunWith(PowerMockRunner.class)
#PrepareForTest( { InternetAvailabilityChecker.class })
public class MyActivityPowerMockTest {
#Test
#Ignore
public void test()
{
final IInternetAvailabilityChecker checker = mock(IInternetAvailabilityChecker.class);
when(checker.isInternetAvailable()).thenReturn(false);
mockStatic(InternetAvailabilityChecker.class);
expect(InternetAvailabilityChecker.create(any(Activity.class))).andReturn(checker);
replay(InternetAvailabilityChecker.class);
final MyActivity objectUnderTest = new MyActivity();
objectUnderTest.onResume();
// Verify that the method InternetAvailabilityChecker.create was called
verify(InternetAvailabilityChecker.class);
// TODO: Verify that Utils.showMessageBox has been invoked
}
}
You appear to be missing a Maven dependency. According to this query the annotations are supplied by:
org.powermock / powermock-core
org.powermock / powermock-easymock-single-jar-release-full
org.powermock / powermock-mockito-single-jar-release-full

Categories

Resources