What is the difference between `assertThatCode()` and `assertThatThrownBy()` in AssertJ?

In AssertJ, both

assertThatCode(…).isInstanceOf(…) and assertThatThrownBy(…).isInstanceOf(…) seem to work similarly.

How do they differ, and why would I choose one over the other?

I also noticed that assertThatThrownBy() allows chaining doesNotThrowAnyException().

What’s the proper usage for each?

I had this confusion too.

One practical difference I noticed: assertThatThrownBy() will fail immediately if no exception occurs, whereas assertThatCode() lets you explicitly assert no exception.

So for negative testing (code should not fail), assertThatCode().doesNotThrowAnyException() reads much better.

Example:

// Expecting exception
assertThatThrownBy(() -> service.readFile("missing.txt"))
    .isInstanceOf(FileNotFoundException.class);

// Expecting no exception
assertThatCode(() -> service.processFile("valid.txt"))
    .doesNotThrowAnyException();

Personally, I use assertThatThrownBy for exception validation and assertThatCode for asserting code is safe. It helps maintain clarity in my test suite.

From my experience, I think of it this way: assertThatThrownBy() is for when you expect an exception, while assertThatCode() is for when you mostly don’t expect one but still want to assert.

  • assertThatThrownBy(() -> …) is great when testing error scenarios; you can check the type, message, and even cause.

  • assertThatCode(() -> …).doesNotThrowAnyException() is handy when testing utility methods that should never fail, especially in refactoring scenarios.

It’s mostly about semantics, your intent is clearer when you pick the right one.

I ran into this myself when migrating tests from JUnit to AssertJ. The key difference is intent:

assertThatThrownBy() is for asserting that an exception is thrown. You pass it a lambda, and then chain assertions like .isInstanceOf(IOException.class).hasMessageContaining("foo").

assertThatCode() is for asserting things about code that may or may not throw. Most often I use it with .doesNotThrowAnyException() to explicitly check that no exception occurs.

For example:

assertThatThrownBy(() -> doSomethingRisky())
    .isInstanceOf(IOException.class)
    .hasMessageContaining("disk");

assertThatCode(() -> doSomethingSafe())
    .doesNotThrowAnyException();

Using the right method makes your tests more readable and communicates intent clearly.