How to write junit test for exceptions which are explicitly thrown - java

I have a method that takes in the String, and check if it contains another string. If it does, then it throws a custom exception.
Class Test{
String s2="test";
public void testex(String s1){
if(s1.contains(s2))
throw new customException();
}
}
I am trying to write a unit test for this:
#Test (expected = customException.class){
when(s1.contains(s2)
.thenThrow(new customException());
}
However, my test is failing with the error as-- java.lang.Exception: Unexpected exception, expected customException but was<org.mockito.exceptions.misusing.MissingMethodInvocationException>

This test doesn't seem to be particularly useful, but I believe your issue is that Mockito's when() expects a method call for a mocked object.
#Test(expcted = CustomException.class)
public void testExMethod() {
#Mock
private Test test;
when(test.testEx()).thenThrow(CustomException.class);
test.testEx("test string");
}

I'm not quite following your example test. It looks like you're mocking your actual class with Mockito rather than writing a junit test. I would write a test like this:
With junit's assertThrows method:
#Test
void stringContainingThrowsError() {
Test myClassThatImTesting = new Test();
assertThrows(CustonException.class, () -> myClassThatImTesting.testex("test"))
}
With a normal assertion:
#Test
void stringContainingThrowsError() {
Test myClassThatImTesting = new Test();
try {
myClassThatImTesting.testex("test");
fail();
} catch (Exception ex) {
assertTrue(ex instanceof CustomException);
}
}

Related

Mockito: Cannot throw exception in Java Unit Test

I have the following service and test methods and I am trying the code execute catch (ApplicationException e) { } block.
public abstract class ApplicationException extends RuntimeException {
// ....
}
public void create(Request request) {
try {
// ...
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
}
}
Here is the test method:
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
// variable defnitions and stubbings (code omitted)
willAnswer( invocation -> { throw new RuntimeException("abc msg"); })
.given(productService).create(request);
// or
// doThrow(new RuntimeException()).when(productService).create(request);
// service method call
productService.create(Request request);
}
When I debug the code, I get error on doThrow line:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
So, how can I solve the problem?
As #Jesper mentioned in comment you are not using Mockito properly.
For your test case you need to test that your ProductService.create method will handle an error in a given scenario. Let's imagine that your code looks like this.
class ProductService {
private SomeOtherService someOtherService;
public void create(Request request) {
try {
someOtherService.execute();
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
enter code here
throw new MyException(e); // Here you can do something else
}
}
So someOtherService.execute can throw ApplicationException. We need to test if our ProductService.create will catch that exception and do some processing. In the example we will just throw a different type of exception.
#Mock
private SomeOtherService mockOtherService;
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
doThrow(new ApplicationException()).when(someOtherService).execute();
given(productService.create(request)).willThrow(new MyException());
}
So main difference from your example is that we are telling the SomeOtherService mock what it should do when execute method is called. This is allowed and Mockito knows how to work with mocks.
In your example you were trying to pass a real object not a mock. #InjectMock annotation is a shorthand for this
this.productService = new ProductService(mockSomeOtherService);
So it creates a new object with its dependency mocked. More about this you can find here https://stackoverflow.com/a/16467893/2381415.
I didn't run this code or test it so do not C/P it.
Hope it helps you understand what was wrong with your approach.

Using PowerMockito with ArgumentCaptor

I simply try to test the following part of my service method:
if (isDeleted) {
LoggingUtils.info("Deleted. ingredientUuuid: {}", ingredient.getUuid());
}
I try to use the following approach in order to catch the values passed to the static method:
// #RunWith(MockitoJUnitRunner.class)
#RunWith(PowerMockRunner.class)
public class DemoTest {
#Test
public void test() {
// code omitted
Page<IngredientDTO> result = ingredientService.findAll(request,sort);
PowerMockito.mockStatic(LoggingUtils.class);
ArgumentCaptor<String> arg1 = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<UUID> arg2 = ArgumentCaptor.forClass(UUID.class);
PowerMockito.verifyStatic(LoggingUtils.class, times(1));
LoggingUtils.info(arg1.capture(), arg2.capture());
// ...
}
}
When debugging the test, it throws "The class com.company.common.LoggingUtils not prepared for test." pointing the following line:
PowerMockito.mockStatic(LoggingUtils.class);
So, how can I fix this problem?
Late answer, sorry for that, but maybe it still helps: Maybe you simply forgot the #PrepareForTest for your static class?
// #RunWith(MockitoJUnitRunner.class)
#RunWith(PowerMockRunner.class)
#PrepareForTest(LoggingUtils.class) // <-- Required, otherwise you'll get exactly that "not prepared for test" error
public class DemoTest {
[...]

Java + Powermockito: How to Replace or Mock Thread.sleep method

Using PowerMockito, I have been trying to replace or mock the Thread.sleep method.
Wherein, the replacing or mocking method will return and Exception.
I have tried the following examples but no luck:
PowerMockito.replace(PowerMockito.method(Thread.class, "sleep", long.class))
.with((object, method, arguments) -> {
throw new Exception(someRandomExceptionMessage);
});
PowerMockito.when(Thread.class, "sleep", anyLong()).thenThrow(new Exception(someRandomExceptionMessage));
PowerMockito.when(Thread.class, "sleep", 1000L).thenThrow(new Exception("An Exception"));
I guess you have an underTest class calling a function that is using Thread.sleep?
You can rather write your test in this way :
if you have a delay variable that returns the execution duration, you can mock the returned value instead of directly mocking Thread.sleep and then test your exception with #Test(expected = Exception.class) or Exception thrownException = assertThrows() depending on wether you are using JUnit 4 or JUnit 5
if you are using JUnit 5, you can simply use assertTimeout(Duration.ofSeconds(10),() -> { underTest.yourMethodCallingThreadSleep())
if using Mockito, the last version can allows you to mock static methods
Take as a suggestion and a simple way to write your test.
This should work. It is important to note the #PrepareForTest needs to refer the method calling Thread.sleep(), not Thread itself.
class ClassCallingSleep {
public static void methodCallingSleep() throws InterruptedException {
System.out.println("TEST 1");
Thread.sleep(100L);
System.out.println("TEST 2");
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassCallingSleep.class})
public class SleepTest {
#Test
public void test() throws Exception {
PowerMockito.mockStatic(Thread.class);
PowerMockito.doThrow(new InterruptedException("HAHA!")).when(Thread.class);
Thread.sleep(Mockito.anyLong());
ClassCallingSleep.methodCallingSleep();
}
}
Output is as follows (that is, TEST 2 above is not reached).
TEST 1
java.lang.InterruptedException: HAHA!

Mockito How to mock and assert a thrown exception

I have this junit:
#RunWith(MockitoJUnitRunner.class)
public class SecurityManagerServiceTest {
#Mock
private SecurityManagerService securityManagerService = mock(SecurityManagerService.class);
#Test
public void testRequireAll() {
when(securityManagerService.loggerUser()).thenReturn(fakeUser());
doCallRealMethod().when(securityManagerService).requireRight(anyString());
//given(securityManagerService.restoreRight("a")).willThrow(SecurityException.class);
when(securityManagerService.restoreRight("a")).thenThrow(SecurityException.class);
}
but I have this error:
unnecessary Mockito stubbings
I also tried:
#Mock
private SecurityManagerService securityManagerService = mock(SecurityManagerService.class);
#Test
public void testRequireAll() {
when(securityManagerService.loggerUser()).thenReturn(fakeUser());
doCallRealMethod().when(securityManagerService).requireRight(anyString());
given(securityManagerService.restoreRight("a")).willThrow(SecurityException.class);
}
The problem is that you are stubbing, but not really testing anything. And if you are not testing anything, then there is no need for stubbing. That's why you have unnecessary Mockito stubbings.
I assume that you want to test your SecurityManagerService. If you want to do that, you need to create an instance or have a bean of that type, but not a mock. Then you call the method that you want to test and assert that you get the expected result.
If you expect to get an exception you can test it like this:
JUnit4, just enhance you #Test annotation:
#Test(expected=SecurityException.class)
JUnit 5:
#Test
void testExpectedException() {
Assertions.assertThrows(SecurityException.class, () -> {
//Code under test
});
}

Can #Before and/or #After methods inspect the expected parameter?

Part of a test fixture checks that no errors were logged during a test:
#After
public void testname() {
if(accumulatedErrors()) {
fail("Errors were recorded during test");
}
}
But for a test that is expected to fail, like this:
#Test(expected = IllegalStateException.class)
public void shouldExplode() throws Exception {
doExplodingStuff();
}
the #After method should invert the check:
#After
public void testname() {
if (failureIsExpected()) {
assertTrue("No errors were recorded during test", accumulatedErrors());
} else {
assertFalse("Errors were recorded during test", accumulatedErrors());
}
}
Is there a way to inspect the expected parameter of the executed test from the #After method?
Of course, the test could specify expectToFail=true or something like that, but I would like to avoid that duplication.
Why you cannot add assertTrue or assertFalse in each test method ?
You solution seems to me too complicated.
Method annotated with #After should be used to release resources.
Using catch-exception, you can move the check for an exception inside the method instead of outside the method:
#Test
public void shouldExplode() throws Exception {
catchException(this).doExplodingStuff();
assertTrue(caughtException() instanceof IllegalStateException);
}

Categories

Resources