How to assert "N" exceptions have been thrown in this unit test? - java

I've got the following unit test, which works almost fine:
#Test(expectedExceptions = {IllegalArgumentException.class}, expectedExceptionsMessageRegExp =
PasswordValidator.INVALID_PASSWORD)
public void testInvalidPasswordsThrowException() throws Exception {
for (String invalidPassword: getInvalidPasswords()){
new LaxPasswordValidator(invalidPassword);
}
}
private String[] getInvalidPasswords() {
return new String[] {INVALID_PASSWORD_1, INVALID_PASSWORD_2, INVALID_PASSWORD_3, INVALID_PASSWORD_4,
INVALID_PASSWORD_5, INVALID_PASSWORD_6, INVALID_PASSWORD_7, INVALID_PASSWORD_8, INVALID_PASSWORD_9,
INVALID_PASSWORD_10};
}
As you can see, it is just asserting that new LaxPasswordValidator(invalidPassword) works as expected and throws an exception.
Problem: It is just taking INVALID_PASSWORD_1 into account, so it stops in the first iteration; it launches the exception but does not continue checking the other passwords. How can I make it test them all? Thanks

You must annotate the method as #DataProvider
#DataProvider(name = "invalid-passwords")
public Object[][] getInvalidPasswords() {
return new String[][]{
{"INVALID_PASSWORD_1"},
{"INVALID_PASSWORD_2"},
{"INVALID_PASSWORD_3"}
};
}
and annotate the #Test method to use this dataprovider for the parameters.
#Test(expectedExceptions = {IllegalArgumentException.class},
expectedExceptionsMessageRegExp = PasswordValidator.INVALID_PASSWORD,
dataProvider = "invalid-passwords")
public void testInvalidPasswords(String password) throws Exception {
new LaxPasswordValidator(password);
}

Related

Java NegativeTest private method with Reflection to catch custom ApplicationException

So I'm testing a AccountService class with a mocked databaselayer.
In this AccountService class there is a private method that checks the input received from UI according to a regex.
The positive test I wrote is working fine:
#Test
public void testEmailPatroonCorrect() throws Exception{
//Correcte emails
List<String> emails = new ArrayList<>();
emails.add("user#domain.com");
emails.add("user#domain.co.in");
emails.add("user.name#domain.com");
emails.add("user_name#domain.com");
emails.add("username#yahoo.corporate.in");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatCode(() -> {
for(String email : emails){
method.invoke(AccountService,email);
}}).doesNotThrowAnyException();
}
However for the negative test (a list with wrong email patterns) even with only one object in the list for simplicity
#Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username#yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatThrownBy(()->{
for(String email : emails){
method.invoke(AccountService,email);
}
}).isInstanceOf(ApplicationException.class).hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
The exception thrown during test is: java.lang.reflect.InvocationTargetException. In the application the ApplicationException gets caught just fine.
Question is how can I write a proper test for a list of wrong email patterns? (without using #VisibleForTesting functionality since it's a school project).
Many thanks!
The InvocationTargetException wraps the exception thrown within the reflectively invoked method. So you may catch the InvocationTargetException and rethrow its cause, but I’d put that into a utility method, like
public interface TestMethod<D,A> {
void invoke(D d, A a) throws Throwable;
}
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return (d,a) -> {
try {
method.invoke(d, a);
} catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
};
}
which you can use like
#Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username#yahoo.com");
TestMethod<AccountService, String> method
= method(AccountService.class, "checkEmailPatroon", String.class);
assertThatThrownBy(() -> {
for(String email : emails){
method.invoke(AccountService, email);
}
}).isInstanceOf(ApplicationException.class)
.hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
The shape of the TestMethod interface allows the alternative implementation like
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return MethodHandleProxies.asInterfaceInstance(
TestMethod.class, MethodHandles.lookup().unreflect(method));
}
Thanks to Holger I was able to write a working test for it's purpose.
#Test
public void testEmailPatroonFoutLoop() throws Throwable {
//Verkeerde emailpatronen
List<String> wrongEmails = new ArrayList<>();
wrongEmails.add(".username#yahoo.com");
wrongEmails.add("username#yahoo.com.");
wrongEmails.add("usernameyahoo.com");
wrongEmails.add("username#yahoo.c");
wrongEmails.add("use..rname#yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
int countedWrongEmails = 0;
for(String email : wrongEmails){
try{
method.invoke(accServ,email);
}
catch (InvocationTargetException ie){
Exception e = (Exception) ie.getTargetException();
if(e.getMessage().equals(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg())){
countedWrongEmails++;
}
}
}
assertThat(countedWrongEmails).isEqualTo(wrongEmails.size());
}
Although I see the benefits and elegance of writing a TestMethod interface, I however do not yet possess the knowledge to grasp it's complexity. So I will stick to this test that I'll be able to explain on the verbal exam.

Testing method having CompletableFuture.allOf using mockito

I have a method called doParallelThings:
public Dummy doParallelThings(Map<String, String> mapp) throws Exception {
Dummy dummy = new Dummy();
CompletableFuture<Ans1> one = firstService.getOne(mapp.get("some1"), mapp);
CompletableFuture<Ans2> two = secondService.getTwo(headersMap.get("some2"), mapp);
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(one, two);
try {
combinedFuture.get();
dummy.setOne(one.get());
dummy.setTwp(two.get());
} catch (Throwable e) {
}
return dummy;
}
Code works fine but when I'm trying to test it,
combinedFuture.get(); goes to infinite loop.
Unit test is as below:
#Mock
private CompletableFuture<Void> ans;
#Test
public void testDoParallelThings() throws Exception {
PowerMockito.mockStatic(CompletableFuture.class);
PowerMockito.when(CompletableFuture.allOf(any())).thenReturn(ans);
when(ans.get()).thenReturn(null);
Dummy dummy = dummyService. doParallelThings(mockMap);
assertNotNull(dummy);
}
I have also added #RunWith(PowerMockRunner.class)
#PrepareForTest({CompletableFuture.class}) above the test class.
What am I missing?
when(firstService.getOne(any(), any())).thenReturn(CompletableFuture.completedFuture(mockOne));
solved my problem

How to test a method using a PrintWriter?

I have following method:
#Component
public class WriteCsvToResponse {
private static final Logger LOGGER = LoggerFactory.getLogger(WriteCsvToResponse.class);
public void writeStatus(PrintWriter writer, Status status) {
try {
ColumnPositionMappingStrategy mapStrategy
= new ColumnPositionMappingStrategy();
mapStrategy.setType(Status.class);
String[] columns = new String[]{"id", "storeId", "status"};
mapStrategy.setColumnMapping(columns);
StatefulBeanToCsv btcsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.withMappingStrategy(mapStrategy)
.withSeparator(',')
.build();
btcsv.write(status);
} catch (CsvException ex) {
LOGGER.error("Error mapping Bean to CSV", ex);
}
}
I have no idea how to test it properly using mockito.
Use it to wrap the object status into csv format.
I used StringWriter to wrap the response in it.
There are no more details left, but it seems I have to create some words to pass the validation :)
You do not need mockito to test this method, only a java.io.StringWriter.
Here is how you can write the test for a nominal use:
#Test
void status_written_in_csv_format() {
// Setup
WriteCsvToResponse objectUnderTest = new WriteCsvToResponse ();
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
// Given
Status status = ...
// When
objectUnderTest.writeStatus(printWriter, status);
// Then
String actualCsv = stringWriter.toString();
assertThat(actualCsv.split("\n"))
.as("Produced CSV")
.containsExactly(
"id,storeId,status",
"42,142,OK");
}
This example assume some things about your Status object, but you have the general idea.
For assertions, I use AssertJ, but you can do the same with JUnit5 built-in assertions.
Hope this helps !
With a bit of a refactoring, where the Builder is a Spring Bean injected into this component.
You can then mock that builder to return a mocked StatefulBeanToCsv, specifically the write method, where you write the conditions and assertions. If you encounter an error, you throw some unchecked exception, like IllegalStateException, if everything is alright, you don't throw anything
you can write a test like this and change your input in write method:
#Test
public void test() {
WriteCsvToResponse writeCsvToResponse = mock(WriteCsvToResponse.class);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
write((Status)args[1]);
return null;
}
}).when(writeCsvToResponse).writeStatus(any(PrintWriter.class),any(Status.class));
writeCsvToResponse.writeStatus(writer, status);
}
public void write(Status status) {
// do anythings you like with status
}

Testng test for specific exception with message

I am trying to test if a method throws a specific exception with it's message like this :
#DataProvider(name = "correctPairs")
public Object[][] expectedResultsTest() {
return new Object[][] {
{ null, new NullPointerException("Class cannot be null") },
};
}
#Test(dataProvider = "correctPairs")
public void ormDefinitionClassTest(final Class<?> value, final Throwable e) {
try {
DatabaseManager databaseManager = new DatabaseManager();
databaseManager.findAll(value);
} catch (Throwable ex) {
Assert.assertEquals(ex, e);
}
But it fails with the exception :
java.lang.AssertionError: expected [java.lang.NullPointerException: Class cannot be null] but found [java.lang.NullPointerException: Class cannot be null]
How can I make it check for equality of Exceptions ,by using #DataProvider?
I would use catchThrowable method from AssertJ fluent assertions. This way you can check the exception in test body, like
Throwable t = catchThrowable(() -> databaseManager.findAll(value));
assertThat(t).isInstanceOf(e);
EDIT: The problem here can be that you assume that these two exception objects are equal, but they are not equal objects. What you could do is to assert their type and message separately.
Your mistake lies in the equality test.
Assert.assertEquals(new NullPointerException(), new NullPointerException());
Returns false because the instances of the two exceptions are not the same.
You must compare the classes, then the messages.
class A implements ThrowingRunnable{
#Override
public void run() throws AuthenticationFailedException{
spy.processAuthenticationResponse(mockRequest, mockResponse, authenticationContext);
}
}
assertThrows(AuthenticationFailedException.class,new A());

Test code with Exceptions and with no exceptions at same time (JAVA)

I am writing a test for already built java class function. I am writing tests using Testng and Mockito and have a Data Provider.
This is my Test
#Test(dataProvider = "myProvider", dataProviderClass = StaticDataProvider.class,
expectedExceptions = SomeException.class)
public void myControllerTest(String argument) throws Exception {
// Mocked object bussiness\
Boolean resultantObject = business.getList(argument);
Assert.assertTrue(resultantObject);
}
This is my Controller which I want to test
public Boolean controller(String argument) {
if(argument != null) {
throw new someException();
} else {
System.out.println("Sucess");
return true;
}
}
This is my Data Providor
#DataProvider(name = "myProvider")
public static Object[][] getDirectoryList() throws Exception {
Object[][] result = null;
// case1 throws SomeException
String testData1 = null;
// case2 don't throw exception
String testData2 = "String";
result = new Object[][] { { testData1 }, { testData2 } };
return result;
}
The problem here I am facing is, I don't want to create another test just to test both buggy and non buggy code and complete my test coverage using a single test case. But when I put Expected Exception on top, it fails on correct code, and when I dont, it fails on buggy code.
NOTE: This is example code and may not work, this is just to take an idea of scenario I am working on and what I am expecting.
Even if you ignore the "one test, one assertion" purist perspective, I think most people agree you should split tests that involve error conditions from tests that prove normal behaviour.
If you want to test multiple error conditions within one test (or if you're really keen on continuing with your plan), you can use this pattern:
try {
// something that should cause an exception
fail("Exception expected");
} catch (ExactlyTheRightException e) {
// ignored
}

Categories

Resources