Skip to content

Register AssertablePublishedEvents in test ApplicationContext if AssertJ is on the classpath #1110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Nimelrian opened this issue Mar 14, 2025 · 4 comments
Assignees
Labels
in: test support Spring Boot integration testing type: improvement Minor improvements
Milestone

Comments

@Nimelrian
Copy link

Nimelrian commented Mar 14, 2025

Currently used spring-modulith version: 1.2.4

We're using JGiven for our tests to generate additional documentation.
When using JGiven with Spring, BDD style test steps are located inside stage classes which can then have Spring beans injected into them via @Autowired.

As an aside, JGiven also does not support per-class test lifecycles and requires adding the stages as beans into the test context. As such, it would be nice if @ApplicationModuleTest would allow for additional include filters to be set. As of now, I have to @Import the stages individually.

Example:

@ApplicationModuleTest
@TestInstance(Lifecycle.PER_METHOD) // Enforced by JGiven
@Import({
    TransactionServiceTestStages.Given.class,
    TransactionServiceTestStages.When.class,
    TransactionServiceTestStages.Then.class})
@EnableJGiven
class TransactionServiceTest
    extends SpringScenarioTest<
        TransactionServiceTestStages.Given,
        TransactionServiceTestStages.When,
        TransactionServiceTestStages.Then> {
  @Test
  void when_a_transaction_is_created_a_transaction_created_event_should_be_published() {
    when().create_is_called_with(TransactionTestFixtures.validCreateTransactionCommand);
    then().an_event_of_type_$_should_have_been_published(TransactionCreated.class);
  }
}
class TransactionServiceTestStages {
  @JGivenStage
  static class Given extends Stage<Given> {
    // ...
  }

  @JGivenStage
  static class When extends Stage<When> {
    @Autowired TransactionService transactionService;

    When create_is_called_with(CreateTransactionCommand createTransactionCommand) {
      var command =
          new AuthorizedCommand<>(UserId.SYSTEM, createTransactionCommand);
      transactionService.create(command);
      return self();
    }
  }

  @JGivenStage
  static class Then extends Stage<Then> {
    @Autowired
    PublishedEvents publishedEvents;

    Then an_event_of_type_$_should_have_been_published(Class<?> eventType) {
      assertThat(publishedEvents.ofType(eventType)).isNotEmpty();
      return self();
    }
  }
}

The above test works, because the ModuleContextCustomizerFactory does register PublishedEvents on the application context (https://github.com/spring-projects/spring-modulith/blob/1.2.9/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java#L89). However, I'm using AssertJ and would like to use the AssertablePublishedEvents API. But this only can be injected as a parameter into the test methods and is not registered on the application context.

Would it be possible to detect the presence of AssertJ in the context customizer and register an AssertablePublishedEvents bean if AssertJ is present?

odrotbohm added a commit that referenced this issue Mar 17, 2025
… AssertJ is on the classpath.

We now check for the presence of AssertJ on the classpath and rather register an instance of ApplicationPublishedEvents in the ApplicationContext if present.
@odrotbohm
Copy link
Member

This was easy enough to add. Would you mind checking the 1.4 snapshots?

@odrotbohm odrotbohm self-assigned this Mar 17, 2025
@odrotbohm odrotbohm added in: test support Spring Boot integration testing type: improvement Minor improvements labels Mar 17, 2025
@odrotbohm odrotbohm added this to the 1.4 M3 milestone Mar 17, 2025
@odrotbohm odrotbohm changed the title AssertablePublishedEvents not autowireable / not registered as bean Register AssertablePublishedEvents in test ApplicationContext if AssertJ is on the classpath Mar 17, 2025
@Nimelrian
Copy link
Author

This was easy enough to add. Would you mind checking the 1.4 snapshots?

Will have to take a look at this. Can't add other maven repositories to my maven config due to corporate limitations. Would have to rebuild a minimal example on my private machine.

One thing regarding this: In my current setup (Pulling PublishedEvents from context) I noticed that the events aren't cleared between test cases. This would be a must-have. Right now I had to switch to Spring Boot's regular @RecordApplicationEvents annotation and inject the ApplicationEvents interface instead.

These are cleared between runs / reinstantiated via a TestExecutionListener.

@odrotbohm
Copy link
Member

For PublishedEvents scoped to the individual test, use (Assertable)PublishedEvents as a test method parameter.

@Nimelrian
Copy link
Author

Hmm, yeah, hoped I could avoid that so I don't need to clutter all of my JGiven tests with

@Autowired
void test(AssertablePublishedEvents events) {
  given().published_events_are_recorded_on(events)
    .and().more_setup();
  // when, then
}

But I guess it's just something I have to swallow. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test support Spring Boot integration testing type: improvement Minor improvements
Projects
None yet
Development

No branches or pull requests

2 participants