Multiply conditions set in AssertJ assertions? - java

I'm trying to set multiply conditions on the assertJ and could not find in it examplesGit.
I currently write:
assertThat(A.getPhone())
.isEqualTo(B.getPhone());
assertThat(A.getServiceBundle().getId())
.isEqualTo(B.getServiceBundle().getId());
But want to have something like:
assertThat(A.getPhone())
.isEqualTo(B.getPhone())
.And
(A.getServiceBundle().getId())
.isEqualTo(B.getServiceBundle().getId());
As if I use chaining this won't work because I need difference data (id and not phone). is there any possibility to mix it all to a one-assertJ command? It doesn't look like there could be any possibility for this (algorithm wise) but maybe some other idea to && on statements?
Thanks

You could use soft assertions with AssertJ to combine multiple assertions and evaluate these in one go. Soft assertions allow to combine multiple assertions and then evaluate these in one single operation. It is a bit like a transactional assertion. You setup the assertion bundle and then commit it.
SoftAssertions phoneBundle = new SoftAssertions();
phoneBundle.assertThat("a").as("Phone 1").isEqualTo("a");
phoneBundle.assertThat("b").as("Service bundle").endsWith("c");
phoneBundle.assertAll();
It is a bit verbose, but it is an alternative to "&&"-ing your assertions. The error reporting is actually quite granular, so that it points to the partial assertions which fail. So the example above will print:
org.assertj.core.api.SoftAssertionError:
The following assertion failed:
1) [Service bundle]
Expecting:
<"b">
to end with:
<"c">
Actually this is better than the "&&" option due to the detailed error messages.

An alternative to assertJ's SoftAssertions is JUnit's assertAll:
import static org.junit.jupiter.api.Assertions.assertAll;
assertAll(
() -> assertThat("a").as("Phone 1").isEqualTo("a"),
() -> assertThat("b").as("Service bundle").endsWith("c")
);

Related

Java Assertions : How to assert for 2 fields on same value

In my code, I have to assert one value against 2 fields. This is what I have to do :
assertThat(request.get(0).name()).isEqualTo("ABC");
assertThat(request.get(0).name2()).isEqualTo("ABC");
How can I use one single line assertion for the above 2 lines?
For example to explain more what I need :
Is there a way I can achieve something like :
assertThat(request.get(0).name() && request.get(0).name2()).isEqualTo("ABC");
How can I use one single line assertion for the above 2 lines?
Why do you want to do such a thing ?
By trying to try too clever, you will get two drawbacks :
you will make your test more complex to read and to maintain.
you will lose the relevant feedback information as a test fails
Actually your test is fine.
If any of these two values doesn't respect the assertion, you have the exact line that spots the issue and you also have a relevant information message.
As a hint, you could maybe just remove the duplication :
final String expected = "ABC";
assertThat(request.get(0).name()).isEqualTo(expected);
assertThat(request.get(0).name2()).isEqualTo(expected);
I don't want to say that it is bad to make multiple assertions in a same statement. Not at all.
I say only that you have to adapt your way of asserting to the tools you are using.
And about it, you don't specify the matcher tool.
If the matcher tool provides a support to make this kind of assertion, use it.
Otherwise, don't make it in a raw way otherwise you will lose the benefit of getting useful failure test messages.
Here is an example with AssertJ that provides this feature out of box.
#Test
void namesEquals() {
List<Request> requests = new ArrayList<>();
requests.add(new Request("ABC", "ABD"));
Assertions.assertThat(requests.get(0)).extracting(Request::name, Request::name2)
.containsExactly("ABC", "ABC");
}
And in this failing test, you will get a useful information message :
java.lang.AssertionError:
Expecting:
<["ABC", "ABD"]>
to contain exactly (and in same order):
<["ABC", "ABC"]>
but some elements were not found:
<[]>
and others were not expected:
<["ABD"]>
A bit too clever perhaps, but you can try this:
assertTrue(Stream.of(request.get(0).name(), request.get(0).name2())
.allMatch("ABC"::equals));
Or you can give this a spin:
assertThat(Arrays.asList(request.get(0).name(), request.get(0).name2()),
Every.everyItem(IsEqual.equalTo("ABC")));
something like:
assertThat(request.get(0).name().equals( request.get(0).name2()) ?
request.get(0).name() : "false").isEqualTo("ABC");

how to express this special array assertion in code?

I am currently using FEST or AssertJ for assertion.
and I run into a knot that I want to assert the flowing array:
[1,2,2,2,2,2,2]
So how do I write the assertion like
assertThat(arr).contains(1,atIndex(0)).containsTheOthers(2)
I don't see containsOthers in FEST or I miss something equal?
I am a bit surprise FEST or AssertJ can't assert a range of index start from some designated index, since them emphasize on fluent concise assertion code.
or is there good alternative?
As far I have to separate it into two asserts and manually fetch out first element to check and the n fetch out the others to check,totally three lines. That's a mess.
assertThat(arr[0]).contains(1,atIndex(0));
Arrays.copyOfRange(arr,1,arr.length);
assertThat(arr).containsOnly(2);
Using AssertJ, I would write:
assertThat(arr).containsExactly(1,2,2,2,2,2,2);
But note that it will also check the elements order.
FYI, AssertJ also provide these "contains" assertions:
containsSequence
containsSubSequence
containsOnlyOnce
Have a look at the int array assertions javadoc
Why complicate things? The simplest way to write this would be:
assertEquals(new int[]{1,2,2,2,2,2,2}, arr);
Otherwise, if there can be any number of 2s, your second solution to split it into two assertions seems sensible.

How to assert an actual value against 2 or more expected values?

I'm testing a method to see if it returns the correct string. This string is made up of a lot of lines whose order might change, thus usually giving 2 possible combinations. That order is not important for my application.
However, because the order of the lines might change, writing just an Assert statement will not work, since sometimes it will pass the test, and sometimes it will fail the test.
So, is it possible to write a test that will assert an actual string value against 2 or more expected string values and see if it is equal to any of them?
Using the Hamcrest CoreMatcher (included in JUnit 4.4 and later) and assertThat():
assertThat(myString, anyOf(is("value1"), is("value2")));
I would use AssertJ for this:
import static org.assertj.core.api.Assertions.*;
assertThat("hello").isIn("hello", "world");
It's more concise and it will give you a descriptive message when the assertion fails.
I am using the following, I hope this would help:
String expectedTitles[] = {"Expected1","Expected2"};
List<String> expectedTitlesList = Arrays.asList(expectedTitles);
assertTrue(expectedTitlesList.contains((actualTitle)));
You can use Hamcrest for this:
assertThat(testString, anyOf(
containsString("My first string"),
containsString("My other string")));
(I see Joachim just answered very similarly (+1)... i'll add this as another example.)
I read all answers, but the one that seems most compact and expressive to me is using Hamcrest's isOneOf which is already included in JUnit
assertThat(result, isOneOf("value1", "value2"));
which gives you a nice error message when failing.
java.lang.AssertionError:
Expected: one of {"value1", "value2"}
but: was "value"
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
[...]
If your using junit I'd just do something like the following:
assertTrue(myString.equals("Value1") || myString.equals("Value"));
Consider writing a custom hamcrest matcher returned by a method, in this case containsOneOf, i.e.:
assertThat(myString, containsOneOf("value1", "value2"));
In keeping with the "xUnit patterns" you should avoid conditional logic in your matcher, a loop with a break statement should suffice.
Have a look at Hamcrest and xUnit Patterns for more information.
If the content for a line is fixed you can split it at line endings before comparing. Then simply compare each line to a set of expected values.
Something like this:
Set<String> expectedValues = ...
String[] split = text.split("\n");
for(String str : split) {
assert(expectedValues.contains(str));
}
If you want to check that all expected values are present you can assert that expectedValue.remove(str) == true and assert after the loop that the Set is empty. If some lines may occur multiple times you have to use a Bag instead of a Set.
The simplest/most efficient might be
assert str.equals(result1) || str.equals(result2);
This will effectively have no overhead when you don't have assertions turned on.
Assuming the method under test returns an array, you could test using Hamcrest's arrayContainingInAnyOrder.
assertThat(result, is(arrayContainingInAnyOrder("value1", "value2", "value")))
Note: use of is wrapper is purely optional, used only as readability sugar.
I think you can just use assertTrue:
assertTrue(testString.matches("string1|string2"));
Simple solution using AssertTrue. Just create a List.of() the expected values and check is it contains the expected value.
assertTrue(List.of("expected_1", "expected_2").contains("actual))
If you do not have or can't use third-party libraries except junit core, you can use this small helper method:
public static void assertListContains(List<Object> expected, Object actual) {
if (!expected.contains(actual)) {
fail("Expected: " + expected + " Actual: " + actual);
}
}
Advantage, in contrast to other workaround answers, is that you can see what was expected and what was actual:
org.opentest4j.AssertionFailedError: Expected: [1, 2] Actual: 3
It's an old post, but I wanted to have an native easy answer, without having extra libraries to add. :)
So I did :
String e
e = "ear"
j = "jars"
assert (j == "jar" || e == "ear")
or if you want them to be both true
assert (j == "jar" && e == "ear")
This seems to me like the simplest solution ...
assert obtainedValue in [acceptedValue1, acceptedValue2]

problem of testing file worker in java

I have a question which is described below:
What problems would arise for testing a Java class which counts number of words in a file?
The function's signature is below:
public int wordCount(String filename)
Well, this is a junit testing question.
If you know the problem, what is the solution of that?
So your question is what to test for? If yes, I'd say you should check if the definition of "word" is implemented correctly (e.g. is "stack-overflow" one word or two), are new lines handled correctly, are numbers counted as words (e.g. difference between "8" and "eight"), are (groups of special) characters (e.g. a hyphen) counted correctly.
Additionally, you should test whether the method returns the expected value (or exception) if the file does not exist.
This should be a good starting point.
To sfussenegger's list, I'd add the file handling checks: does the method respond correctly to files not found (including null filename), or lacking read permission?
Also, to sfussenegger's correctness list, I'd add whether duplicates count and case sensitivity rules, as well.
Of course, all of this requires that you know how the method is supposed to behave for all of these specifics. It's easy to tell someone to "go count words", but there are subtleties to that assignment.
Which is one of the big benefits of writing a good set of unit tests.
This really sounds like a task for FIT: Framework for Integrated Test. It's an acceptance testing framework that works with ant and JUnit.
One docent of mine did such a task and used this framework. It allows you to write a whole bunch of test cases within one html/wiki table. FIT will interpret each line as a parameter set for the function under test and checks the output.
For example:
This table displays the result of three test cases. Two passed, one failed.
You can use fit if you write sentences and define the number of words in your table. With FIT, they're executed and the result is displayed in a new table.
For further information, please read Introduction to FIT.

Multiple correct results with Hamcrest (is there an or-matcher?)

I am relatively new to matchers. I am toying around with hamcrest in combination with JUnit and I kinda like it.
Is there a way, to state that one of multiple choices is correct?
Something like
assertThat( result, is( either( 1, or( 2, or( 3 ) ) ) ) ) //does not work in hamcrest
The method I am testing returns one element of a collection. The list may contain multiple candidates. My current implementation returns the first hit, but that is not a requirement. I would like my testcase to succeed, if any of the possible candidates is returned. How would you express this in Java?
(I am open to hamcrest-alternatives)
assertThat(result, anyOf(equalTo(1), equalTo(2), equalTo(3)))
From Hamcrest tutorial:
anyOf - matches if any matchers match, short circuits (like Java ||)
See also Javadoc.
Moreover, you could write your own Matcher, which is quite easy to do.
marcos is right, but you have a couple other options as well. First of all, there is an either/or:
assertThat(result, either(is(1)).or(is(2)));
but if you have more than two items it would probably get unwieldy. Plus, the typechecker gets weird on stuff like that sometimes. For your case, you could do:
assertThat(result, isOneOf(1, 2, 3))
or if you already have your options in an array/Collection:
assertThat(result, isIn(theCollection))
See also Javadoc.
In addition to the anyOf, you could also go for the either option, but it has a slightly different syntax:
assertThat(result, either(is(1)).or(is(2)).or(is(3))))

Categories