Home > Enterprise >  AsserJ - chaing together returns and extracting
AsserJ - chaing together returns and extracting

Time:03-04

Sometimes sonar cloud is complaining about number of assertions in tests. I wanted and found out how I can chain assertions one to another, but theres a case where I cannot figure out how I can chain assertions.

import java.util.List;

import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.Test;

import lombok.Builder;
import lombok.Data;

import static org.assertj.core.api.Assertions.assertThat;

class FakeTest
{
    @Test
    void fakeTest()
    {
        // given
        var resStatus = "FINISHED";

        var tc1 = "Test case 1";
        var r1 = "GOOD";

        var tc2 = "Test case 2";
        var r2 = "ALARMING";

        var res1 = Response.builder()
                .status(resStatus)
                .testCaseName(tc1)
                .result(r1)
                .build();
        var res2 = Response.builder()
                .status(resStatus)
                .testCaseName(tc2)
                .result(r2)
                .build();

        var result = Result.builder()
                .responses(List.of(res1, res2))
                .value("PASSED")
                .build();

        // then
        assertThat(result)
                .returns("PASSED", Result::getValue);

        assertThat(result.getResponses())
                .extracting("status", "testCaseName", "result")
                .contains(
                        Tuple.tuple(resStatus, tc1, r1),
                        Tuple.tuple(resStatus, tc1, r2));
    }
}

@Data
@Builder
class Result
{
    private String value;
    private List<Response> responses;
}

@Data
@Builder
class Response
{
    private String status;
    private String testCaseName;
    private String result;
    private String error;
}

How can I do assertions in FakeTest#fakeTest with chaining them instead of splitting to two assertions (one for assertThat(result).returns(...) and then assertThat(result.getResponses()).extracting(...)...)

What I want to achive is:

assertThat(result)
                .returns("PASSED", Result::getValue)
                .extracting(Result::getResponses) // connection between two assertThat(...)
                .extracting("status", "testCaseName", "result")
                .contains(
                        Tuple.tuple(resStatus, tc1, r1),
                        Tuple.tuple(resStatus, tc1, r2));

I've found out that returning Assertion object are different:

  • ListAssert<Response> when doing the chain of second assertion
  • AbstractObjectAssert<capture of ?, List<Response>> when doing merged assertion

CodePudding user response:

extracting(singleParam or lambda) can't return assertions specific to the extracted value type due to java generics limitations, in this case one can inform AssertJ of the type by using asInstanceOf which would look like:

static import org.assertj.core.api.InstanceOfAssertFactories.LIST;

assertThat(result)
                .returns("PASSED", Result::getValue)
                .extracting(Result::getResponses).asInstanceOf(LIST) // static import for readability
                .extracting("status", "testCaseName", "result")
                .contains(
                        Tuple.tuple(resStatus, tc1, r1),
                        Tuple.tuple(resStatus, tc1, r2));

InstanceOfAssertFactories provides types AssertJ supports assertions for.

Another option would be to pass a lambda that extracts the responses and their fields directly (but that's probably of bit too much work).

  • Related