2

I have the following test code which checks the content of a particular directory structure

assertThat(install_should_not_fail).isDirectory().satisfies(isnf -> {
  assertThat(new File(isnf, "maven-metadata-local.xml")).isNotEmpty();
  assertThat(new File(isnf, "1.0")).isDirectory().satisfies(v10 -> {
    assertThat(v10).satisfies(file -> {
      assertThat(new File(file, "install_should_not_fail-1.0.jar")).isNotEmpty();
      assertThat(new File(file, "install_should_not_fail-1.0.pom")).isNotEmpty();
      assertThat(new File(file, "_remote.repositories")).isNotEmpty();
    });
  });
});

and I have several tests which do very similar things. The question is: Can that be made simpler (I know I could refactor out a method which contains exactly that code) but I'm interested more in getting the above code simpler using AssertJ if it's possible?

khmarbaise
  • 92,914
  • 28
  • 189
  • 235

3 Answers3

3

I would suggest an approach that does not use satisfies to avoid the nested blocks:

assertThat(install_should_not_fail).isDirectory();
assertThat(new File(install_should_not_fail, "maven-metadata-local.xml")).isNotEmpty();

File v10 = new File(install_should_not_fail, "1.0");
assertThat(v10).isDirectory();
assertThat(new File(v10, "install_should_not_fail-1.0.jar")).isNotEmpty();
assertThat(new File(v10, "install_should_not_fail-1.0.pom")).isNotEmpty();
assertThat(new File(v10, "_remote.repositories")).isNotEmpty();

I feel this makes the code a bit lighter and more readable (to me at least).

Moreover, I think this is a good candidate for soft assertions so that all the assertions errors are reported instead of failing at the first one.

Joel Costigliola
  • 6,308
  • 27
  • 35
  • many thanks for your suggestions. The funny thing is that I came exactly from such a solution which I replaced with the one in my questions which represents (from my point of view) the structure of a directory. But of course this solution is lighter..I have a large number of them https://github.com/khmarbaise/maven-it-extension/blob/master/itf-maven-plugin/src/test/java/com/soebes/itf/maven/plugin/BasicIT.java And you suggestion about soft assertions is a very good idea. I need to reconsider my needs and may be I should check for a custom assertions (also suggested by Marcin... – khmarbaise Apr 23 '20 at 19:05
  • if you have a lot of tests with this pattern then I agree with Marcin that investing in custom assertions is good option (but bear in mind that you will have to maintain them). – Joel Costigliola Apr 24 '20 at 00:12
3

If you don't need to check whether the files are non-empty, Files::fileNamesIn may come handy. You could do something like:

assertThat(Files.filesNamesIn(dir, /* recursive */ true)).contains(
  basePath + "/maven-metadata-local.xml",
  basePath + "/1.0/install_should_not_fail-1.0.jar",
  basePath + "/1.0/install_should_not_fail-1.0.pom",
  basePath + "/1.0/_remote.repositories")

Otherwise you may refactor this pattern into your own custom assertion. For example, here is an assertion that verifies that the given paths represent non-empty, readable files inside a directory:

public class MyAssertions extends Assertions {
    public static MyFileAssert assertThat(File actual) {
        return MyFileAssert.assertThat(actual);
    }
}

public class MyFileAssert extends AbstractFileAssert<MyFileAssert> {
    public MyFileAssert(File actual) {
        super(actual, MyFileAssert.class);
    }

    public static MyFileAssert assertThat(File actual) {
        return new MyFileAssert(actual);
    }

    public MyFileAssert containsReadableNonEmptyFiles(String... paths) {
        isDirectory();

        List<String> nonExistent = new ArrayList<>();
        List<String> nonFiles = new ArrayList<>();
        List<String> nonReadable = new ArrayList<>();
        List<String> empty = new ArrayList<>();

        for (String path : paths) {
            File file = new File(actual, path);

            if (!file.exists()) {
                nonExistent.add(path);
                continue;
            }

            if (!file.isFile()) {
                nonFiles.add(path);
                continue;
            }

            if (!file.canRead()) {
                nonReadable.add(path);
                continue;
            }

            if (file.length() == 0) {
                empty.add(path);
            }
        }

        if (!(nonExistent.isEmpty() && nonFiles.isEmpty() && nonReadable.isEmpty() && empty.isEmpty())) {
            StringBuilder failMessage = new StringBuilder()
                    .append("Expected directory '")
                    .append(actual)
                    .append("' to contain the following readable, non-empty files:\n");

            for (String path : paths) {
                failMessage.append("  ")
                        .append(path)
                        .append("\n");
            }


            if (!nonExistent.isEmpty()) {
                failMessage.append("The following files don't exist:\n");

                for (String path : nonExistent) {
                    failMessage.append("  ")
                            .append(path)
                            .append("\n");
                }

            }

            // The rest left out for brevity.

            failWithMessage(failMessage.toString());
        }

        return this;
    }
}

The example usage of the above is as follows:

assertThat(install_should_not_fail).containsReadableNonEmptyFiles(
  "maven-metadata-local.xml",
  "1.0/install_should_not_fail-1.0.jar",
  "1.0/install_should_not_fail-1.0.pom",
  "1.0/_remote.repositories")

You may read more about AssertJ's custom assertions here.

Marcin Jedynak
  • 3,697
  • 2
  • 20
  • 19
0

Late answer but could always help future users, since 3.13.0 of assertj you have can use isEmptyDirectory and isDirectoryContaining to check directory content and since 3.19.0 isEmptyFile that checks if your file is empty

Youssef NAIT
  • 1,362
  • 11
  • 27