简体   繁体   中英

JUnit checking if the message thrown by an exception is either `stringA` or `stringB`

In my code I have some pattern like (I tried to simplified as much as possible):

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import java.util.Set;

public void funcSubSet() {
   final Set<String> setA = new HashSet<>(Arrays.asList("a", "b", "c", "d"));
   final Set<String> setB = new HashSet<>(Arrays.asList("a"));
   Preconditions.checkArgument(setB.constainsAll(setA),
                               "The strings %s are present in setA but not in setB",
                               Joiner.on(", ").join(setA.stream()
                                                   .filter(Predicate.not(setB::contains))
                                                   .iterator())
                               );
}

Basically, this checks if setA is fully contained in setB . If not, throws an exception and prints the elements that are in setA and not be in setB (separated by a comma and a space). When I test it, the problem is that it output the strings not contained in setB in different order sometimes and the following test case fails occasionally.

assertThrows(IllegalArgumentException.class,
             () -> funcSubSet()),
             "The strings b, c, d are present in setA but not in setB")

Sometime the output is like: "The strings d, b, c are present in setA but not in setB".

How do you I make it agnostic of the order? How can I tell hasMessage() or any other assertion that I accept more than one string? I checked and couldn't find anything.

I use JUnit 5!

If you can provide the sets to check from outside in your test (which I would recommend for a good code design and high testability), you can provide a java.util.LinkedHashSet<E> instead of a HashSet for the test. This class ensure the iteration order to be in the order of first insertion, so you get a predictable outcome.

If you cannot choose the actual Set implementation for your test, I would write the test a bit different:

import org.junit.jupiter.api.Assertions;

//...

// expect permutation of:
//The strings b, c, d are present in setA but not in setB

Exception thrownException = Assertions.assertThrows(Exception.class, () -> funcSubSet());

String message = thrownException.getMessage();

Assertions.assertEquals("The strings ", message.substring(0, 12), "message start");
Assertions.assertEquals(" are present in setA but not in setB", message.substring(19), "message end");
String variables = message.substring(11,19);
Assertions.assertTrue(variables.contains(" b"), "contains b");
Assertions.assertTrue(variables.contains(" c"), "contains c");
Assertions.assertTrue(variables.contains(" d"), "contains d");

With Assertions.assertThrows you could also expect a fixed String and work with the caught exception for further details. org.junit.jupiter.api.Assertions is part of JUnit and does not need 3rd party dependencies like AssertJ.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM