I have created a JUNIT test cases for elasticsearch CRUD operation i have given the code below. After code reviewing phase i got an update from team that i have covered all the positive scenario of test cases still not yet covered the negative scenarios. I am not aware of handling the negative use cases.
#Test
void findById() throws Exception {
EmployeeInformation EmployeeGet = Eservice.findById("elcrud", "2");
assertNotNull(EmployeeGet.getId());
assertNotNull(EmployeeGet.getFirstName());
assertNotNull(EmployeeGet.getLastName());
}
#Test
void deleteProfileDocument() throws Exception {
String Result = Eservice.deleteProfileDocument("elcrud", "3");
System.out.println(Result);
assertEquals(Result, "DELETED");
}
#Test
void search() throws Exception {
List<EmployeeInformation> Emp=Eservice.searchByTechnology("Lucidworks","elcrud");
System.out.println(Emp.size());
int Result = Emp.size();
assertTrue(Result >= 0 );
}
#Test
void searchByName() throws Exception {
List<EmployeeInformation> Emp=Eservice.findProfileByName("junit","elcrud");
System.out.println(Emp.size());
int Result = Emp.size();
assertTrue(Result >= 0 );
}
Could some one help me to implement the negative scenario of JUNIT test cases for above code?
I think you tech team wants a test if the operation of ES failed, give no results or any other unexpected scenario happens.
One example could be the deletion of a profile document:
You already covered the test if the delete operation is successful. But you dont have a test if this operation failed or is not handled successful.
#Test
void deleteProfileDocument() throws Exception {
//here you delete a profile which is NOT in the index
String Result = Eservice.deleteProfileDocument("elcrud", "3");
System.out.println(Result);
//and here you asssert the negative result. (Not sure which result will come)
assertEquals(Result, "NOT_FOUND");
}
I also see that on your test you throw an exception in case of an error. This could be another good negative test scenario. So, if you can send an operation to ES and this operation throws an exception you can create a test to expect this exception.
For Junit4 you could use the following:
#Test(expected = YourExpectedException.class)
For Junit5 you could use this:
Exception exception = assertThrows(YourExpectedException.class, () -> {
Eservice.findProfileByName(Exception values);
});
String expectedMessage = "expected message";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
EDit by addtional questions
If you have a positive and a negeative test, I would suggest to keep them in separate test methods. So there will be no need to comment things out and in.
In your case it could be like:
positve:
#Test
void testUpdateItem_POSITIVE() throws Exception {
....
}
negative:
#Test
void testUpdateItem_NEGATIVE() throws Exception {
....
}
#Test(expected = NotFound.class)
void shouldThrowExceptionWhenProfileIsNotExist() throws Exception {
Eservice.findById("elcrud", "some_id");
}
Instead NotFound place your exception which is thrown when search profile with an id which is not exist
Related
I'm unit testing a Spring boot web app with Mockito. One of my methods is returning a void, but if I try to test it, I get compilation errors.
This is the test I wrote:
public void testDeleteActor()throws NetflixException {
when(actorRepository.findById(1L)).thenReturn(Optional.of(Mockito.any(Actor.class)));
assertEquals(null, service.deleteActorById(Mockito.anyLong());
}
And this is the method I'm trying to test:
#Override
public void deleteActorById(Long id) throws NetflixException {
Actor actor = actorRepository
.findById(id)
.orElseThrow(() -> new NotFoundException("Actor id not found - " + id));
actorRepository.delete(actor);
}
As you can see in the following screenshot, I'm getting an error with my assertEquals() statement:
In your code, your method isn't actually returning null, it's returning nothing (void). That means that you can't write assertions based on what the method returns. This is the reason why the assertEquals() statement is giving you an error.
In stead of testing what the method returns, you can test the expected behaviour of the method. In this example, there are three things we expect:
The method should retrieve the actor by its ID.
The method should throw an exception if no actor was found with the given ID.
The method should delete the actor if it was found.
To implement this these tests, you can use Mockito's verify() and AssertJ's assertThatExceptionOfType(). For example:
#Test
void deleteActorById_retrievesActorByID() {
Actor actor = new Actor();
when(actorRepository.findById(1L)).thenReturn(Optional.of(actor));
service.deleteActorById(1L);
verify(repository).findById(1L);
}
#Test
void deleteActorById_throwsExceptionIfIDNotFound() {
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> service.deleteActorById(1L))
.withMessage("Actor id not found - 1");
}
#Test
void deleteActorById_deletesActorIfIDFound() {
Actor actor = new Actor();
when(actorRepository.findById(1L)).thenReturn(Optional.of(actor));
service.deleteActorById(1L);
verify(actorRepository).delete(actor);
}
I am using Smallrye Mutiniy reactive library in my Quarks application as it is supported natively in Quarks applications.
I'am trying to write unit tests for a service class. I am not sure how to write unit tests for a method that returns Uni/Multi.
A method returning Uni<String>
public Uni<String> hello(final String name) {
final String message = "Hello " + name;
return Uni.createFrom().item(message);
}
Unit implemented for the above method
#Test
void testHello() {
final Uni<String> casePass = hello("Ram");
// assertion passes and all good with this.
casePass.subscribe().with(message -> Assertions.assertEquals("Hello Ram", message));
final Uni<String> caseFail = hello("Ravan");
// It is expected to fail the assertion, and it does. But the test is not failing, instead aseertion fail message simply logged to the console.
caseFail.subscribe().with(message -> Assertions.assertEquals("Hello Sita", message));
}
Console logs
[-- Mutiny had to drop the following exception --]
Exception received by: io.smallrye.mutiny.helpers.UniCallbackSubscriber.onItem(UniCallbackSubscriber.java:71)
org.opentest4j.AssertionFailedError: expected: <Hello Sita> but was: <Hello Ram>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1124)
...
There are several approaches. You can use the utility methods provided in smallrye.io/smallrye-mutiny/guides/testing. However, if, according to your comment, you need more, I would recommend the following approach:
final Uni<Greeting> casePass = hello("Ram");
Greeting g = casePAss.await().atMost(Duration.ofSeconds(5)); // To be sure we don't stay tucked
// Assertions come here
So basically, you block until the item is sent. Avoid await().indefinitely() because it may block your test if the Uni never send an item. Not that await()... throws an exception if the Uni sends a failure.
I would really recommend using the way of testing from SmallRey.
https://smallrye.io/smallrye-mutiny/1.7.0/guides/testing/
You still can get the object out of the multi/uni
use invoke, for example.
public static Uni<String> hello(final String name) {
final String message = "Hello " + name;
return Uni.createFrom().item(message);
}
#Test
public void testUnit() {
UniAssertSubscriber<String> tester = hello("someone")
.invoke( i -> Assertions.assertEquals("Hello someone", i))
.invoke(i -> Assertions.assertNotNull(i))
.subscribe().withSubscriber(UniAssertSubscriber.create());
tester.assertCompleted();
}
#Test
public void secondUnit() {
UniAssertSubscriber<String> tester = hello("none")
.invoke( i -> Assertions.assertEquals("Hello someone", i))
.invoke(i -> Assertions.assertNotNull(i))
.subscribe().withSubscriber(UniAssertSubscriber.create());
tester.assertCompleted();
}
I hope you can use it like that
This function is used to query the database to search for a specific category. The testcase which i wrote for this function covers the entire code by when I see the code coverage using eclipse ecelma it shows red for a specific line. Can someone help me to rectify this?
#Override
public List<Services> searchCategory(String name) throws CategoryNameNotFoundException{
logger.info("{}.{}",new ServicesBoImpl().getClass().getPackageName(), new ServicesBoImpl().getClass().getName());
logger.info("Function: searchCategory(), Information: querying the database for the search categories");
List<Services> searchCategory = jdbcTemplate.query(env.getProperty("searchCategory"), new PreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(1, name+"%");
}
} ,new SearchCategoryRowMapper());
if(searchCategory.size()==0) {
logger.info("Function: searchCategory(), Information: Throwing CategoryNameNotFoundException because the paticular category is not found");
throw new CategoryNameNotFoundException("Category Not Found");
}
return searchCategory;
}
What logic are you trying to cover by writing this UT ? No logic is executed inside test...
Assuming that serviceBoImpl is mock:
#Test(expected = CategoryNameNotFoundException.class)
public void testIfSearchCategoryThrowsException() {
Mockito.doThrow(CategoryNameNotFoundException).when(serviceBoImpl).searchCategory("a!#")
...here execution which calls this method...
}
Remember that this test will not cover logic of searchCategory method as it is throwing an error once it is executed
I am trying to write unit tests for a camel route - its for importing and processing a file
from(fullImportFTP)
.routeId(STUB_FILE_DOWNLOAD_ROUTE_ID)
.onException(Exception.class)
.handled(false)
.log(LoggingLevel.ERROR, STUB_IMPORT_ERROR_CODE)
.end()
.log("Processing Stub file:[${header.CamelFileName}]")
.to(ROUTE_TO_MACE);
from(ROUTE_TO_MACE)
.routeId(STUB_FILE_IMPORT_ROUTE_ID)
.onException(Exception.class)
.handled(false)
.log(LoggingLevel.ERROR, STUB_IMPORT_ERROR_CODE)
.end()
.onException(IOException.class)
.maximumRedeliveries(routesConfig.camelMaximumRetries).redeliveryDelay(routesConfig.camelRedeliveryDelay)
.handled(false)
.log(LoggingLevel.ERROR, STUB_IMPORT_ERROR_CODE)
.end()
.split().tokenizeXML(ITEM).streaming()
.process(processor)
.to("log:route.StubRoute?level=DEBUG")
.end()
.log("Stub file sucessfully processed:[${header.CamelFileName}]");
And below is the unit test:
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class CamelRouteTest {
#EndpointInject(uri = "mock:success_result")
private MockEndpoint successResultEndpoint;
#EndpointInject(uri = "direct:mock-import-stub-download")
private FluentProducerTemplate producer;
#Autowired
private CamelContext camelContext;
#MockBean
RestTemplate restTemplate;
private static final String MOCK_IMPORT_STUB_DOWNLOAD = "direct:mock-import-stub-download";
private static final String TEST_STUB_FILE_LOCATION = "src/test/resources";
#Before
public void setup() throws Exception {
camelContext.getRouteDefinition(STUB_FILE_DOWNLOAD_ROUTE_ID).autoStartup(true).adviceWith(camelContext,
new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith(MOCK_IMPORT_STUB_DOWNLOAD);
interceptSendToEndpoint("log:route.StubRoute?level=DEBUG").skipSendToOriginalEndpoint().to(successResultEndpoint);
}
});
camelContext.start();
}
#Test
public void testFileDownloadRouter() throws Exception {
File file = new File(TEST_STUB_FILE_LOCATION + "/Stub_11092018_162149_59642501.xml");
successResultEndpoint.expectedMessageCount(1);
producer.withBody(file).withHeader(Exchange.FILE_NAME, "Stub_24102018_162149_59642501.xml").send();
successResultEndpoint.assertIsSatisfied();
}
I always get the message count as 0. Here is the ERROR
java.lang.AssertionError: mock://success_result Received message
count. Expected: <1> but was: <0> Expected :<1> Actual :<0>
What am I doing wrong here? I have 2 routes as you can see - the first one actually goes to the second one, so in the unit tests should I have 2 routes too? I haven't added 2 routes because if I debug I can see that it actually goes through the processor and returning the correct result.
First of all: you are using AdviceWith, so you should put the annotation #UseAdviceWith on your testclass. Otherwise the automatic start of the Camel context and the route advice could overlap.
For the missing message on the Mock: Perhaps your test just asserts too early. I guess the producer does not block while the message is processed, but the MockEndpoint assert follows immediately after sending the message. Right after sending the message the received message count is still 0.
To check if waiting helps, you could insert a Thread.sleep(). If it works, you should get rid of the Thread.sleep() and replace it with a Camel NotifyBuilder
Just saw another point. The final to() in your interceptSendToEndpoint chain points to the MockEndpoint instance variable. I think this should point to the MockEndpoint URI, i.e. .to("mock:success_result")
And even one more: you get the first route to advice with getRouteDefinition(STUB_FILE_DOWNLOAD_ROUTE_ID) but in this advice block you advice both routes. That is probably the reason for your problem. The second route is not adviced and therefore your mock is not in place. You have to advice the second route in its own advice block.
#Before
public void setup() throws Exception {
camelContext.getRouteDefinition(STUB_FILE_DOWNLOAD_ROUTE_ID).autoStartup(true).adviceWith(camelContext, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith(MOCK_IMPORT_STUB_DOWNLOAD);
}
});
camelContext.getRouteDefinition(STUB_FILE_IMPORT_ROUTE_ID).autoStartup(true).adviceWith(camelContext, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
interceptSendToEndpoint("log:route.StubRoute?level=DEBUG").skipSendToOriginalEndpoint().to("mock:success_result");
}
});
camelContext.start();
}
Is there a way to get the reason a HystrixCommand failed when using the #HystrixCommand annotation within a Spring Boot application? It looks like if you implement your own HystrixCommand, you have access to the getFailedExecutionException but how can you get access to this when using the annotation? I would like to be able to do different things in the fallback method based on the type of exception that occurred. Is this possible?
I saw a note about HystrixRequestContext.initializeContext() but the HystrixRequestContext doesn't give you access to anything, is there a different way to use that context to get access to the exceptions?
Simply add a Throwable parameter to the fallback method and it will receive the exception which the original command produced.
From https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica
#HystrixCommand(fallbackMethod = "fallback1")
User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
#HystrixCommand(fallbackMethod = "fallback2")
User fallback1(String id, Throwable e) {
assert "getUserById command failed".equals(e.getMessage());
throw new RuntimeException("fallback1 failed");
}
I haven't found a way to get the exception with Annotations either, but creating my own Command worked for me like so:
public static class DemoCommand extends HystrixCommand<String> {
protected DemoCommand() {
super(HystrixCommandGroupKey.Factory.asKey("Demo"));
}
#Override
protected String run() throws Exception {
throw new RuntimeException("failed!");
}
#Override
protected String getFallback() {
System.out.println("Events (so far) in Fallback: " + getExecutionEvents());
return getFailedExecutionException().getMessage();
}
}
Hopefully this helps someone else as well.
As said in the documentation Hystrix-documentation getFallback() method will be thrown when:
Whenever a command execution fails: when an exception is thrown by construct() or run()
When the command is short-circuited because the circuit is open
When the command’s thread pool and queue or semaphore are at capacity
When the command has exceeded its timeout length.
So you can easily get what raised your fallback method called by assigning the the execution exception to a Throwable object.
Assuming your HystrixCommand returns a String
public class ExampleTask extends HystrixCommand<String> {
//Your class body
}
do as follows:
#Override
protected ErrorCodes getFallback() {
Throwable t = getExecutionException();
if (circuitBreaker.isOpen()) {
// Log or something
} else if (t instanceof RejectedExecutionException) {
// Log and get the threadpool name, could be useful
} else {
// Maybe something else happened
}
return "A default String"; // Avoid using any HTTP request or ypu will need to wrap it also in HystrixCommand
}
More info here
I couldn't find a way to obtain the exception with the annotations, but i found HystrixPlugins , with that you can register a HystrixCommandExecutionHook and you can get the exact exception in that like this :
HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixCommandExecutionHook() {
#Override
public <T> void onFallbackStart(final HystrixInvokable<T> commandInstance) {
}
});
The command instance is a GenericCommand.
Most of the time just using getFailedExecutionException().getMessage() gave me null values.
Exception errorFromThrowable = getExceptionFromThrowable(getExecutionException());
String errMessage = (errorFromThrowable != null) ? errorFromThrowable.getMessage()
this gives me better results all the time.