Skip to content

[Feature Request] Consider a way for DB assertions to coexist with org.assertj.core.api.Assertions #329

@jmaniquet

Description

@jmaniquet

Hi github

I like assertj-db and use it on a regular basis.
There is an improvement I would like to see if possible; hence this feature request.

I often find myself having to use both assertj-db assertions and assertj-core assertions in the same class.

Most often it is :

  • Testing insert/update/delete methods : I use AssertJ DB to verify DB state
  • Testing select methods : I use AssertJ core to assert on the result

However both entry point are called the same (Assertions.assertThat) but come from different packages.
The result is I can only have one assertThat as a static import.
I end up with something like this :

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

...

myDao.insert(stuff);
Request request = assertDbConnection
                .request("select foo from bar where toto = ?")
                .parameters("dummy")
                .build();
RequestAssert assert = assertThat(request); // static import there - which is what I would like everywhere
// perform some db assertion there

...
String t = myDao.selectStuff();
Assertions.assertThat(t).isEqualTo(...); // non static import there - both static import with same method name can't coexist

It is not the end of the world, but I was wondering if some improvements could not be made.
I looked into it, and found that AssertJ provide the interface AssertProvider<A> which maybe could be used.
Springframework uses it to provide powerful assertions for their own assertions objects (like in the mvc test infrastructure), while retainaing the integration with Assertions class from AssertJ core.
My understanding is that :

  • The AssertProvider implementation wraps the custom assertion object - for AssertJ DB that would be RequestAssert and its siblings
  • AssertProvider returns the custom assertion object from its only method
  • AssertProvider is then to be passed to the org.assertj.core.api.Assertions.assertThat method
  • The result of that call is the custom assertion object itself, which we can use for the custom assertions

This would look like this :

public static class RequestAssertProvider implements AssertProvider<RequestAssert> {

    private RequestAssert requestAssert;

    public RequestAssertProvider(RequestAssert requestAssert) {
        this.requestAssert = requestAssert;
    }

    @Override
    public RequestAssert assertThat() {
        return this.requestAssert;
    }
}

Given that, we would need a clean way to :

  • Build the RequestAssert from the Request
  • Build the RequestAssertProvider from the RequestAssert
  • Then pass it to the org.assertj.core.api.Assertions.assertThat method

Then in the test class we would only need the assertions class from assertj core :

import org.assertj.core.api.Assertions;
...
RequestAssertProvider assertProvider = ...; // find a way to build this cleanly like we usually build Request
RequestAssert = assertThat(assertProvider);

...

We can then do DB assertions as usual, while retaining the ability to perform core AssertJ assertions without the hassle of the double imports.

Now I'm not naïve enough to think I am the first to consider that problem.
So maybe there is a catch; which I would be interested to know of.

I forked the AssertJ DB repo and gave it a try anyway.
I wrote the RequestAssertProvider like mentioned; as a static inner class for the Request class.

I then altered the Request.Builder by adding this method :

public RequestAssertProvider buildAssert() {
    Request obj = this.build();
    RequestAssert requestAssert = new RequestAssert(obj).as(getDescription(obj));
    return new RequestAssertProvider(requestAssert);
}

Seems like it works.
But it looks like I introduced a cyclic dependency between the Request and RequestAssert classes
Maybe its bad, maybe its not; I'm not sure.
If it's not, I'm willing to iterate on it and submit it as a PR.
Or maybe try another approach.

So would this be useful, and would this be possible ?
What do you think ?

Thank you for reading me

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions