eclipse-vertx / vertx-junit5

Testing Vert.x applications with JUnit 5
Apache License 2.0
44 stars 32 forks source link

A single checkpoint should not supersede a succeedingThenComplete #90

Open doctorpangloss opened 3 years ago

doctorpangloss commented 3 years ago

Describe the feature

Given code like this:

@Test
void testProc(VertxTestContext testContext) {
  var checkpoint = testContext.checkpoint();
  returnsFuture()
    .onSuccess(v -> checkpoint.flag())
    .compose(v -> anotherReturnsFuture())
    .onComplete(testContext.succeedingThenComplete());
}

the user's intent is almost always to flag the checkpoint but to keep running until testContext.succeedingThenComplete() is called with a succeeded future.

Currently, creating a checkpoint like in the above statement will actually end the test as soon as the test thread notices checkpoint.flag() (i.e. the injected testContext.awaitCompletion will be satisfied). This is very clunky.

Use cases

A common use case is to run some side-by-side check independent the test code and use checkpoints to flag that your assertions were actually run. For example you might mock a class and checkpoint.flag() inside a mocked method that runs assertions on its arguments.

Contribution

I can implement this feature.

jponge commented 3 years ago

When there are checkpoints TestContext completes when they have all completed, so onComplete shall also flag a checkpoint.

jponge commented 3 years ago

Also how would you spot that the test context succeedingThenComplete method could eventually be called?

succeedingThenComplete is really a shortcut for completing immediately when one asynchronous operation completes.

doctorpangloss commented 3 years ago

Yes, but what happens is the test completes before succeedingThenComplete 's returned handler is called, because of something with checkpoint.flag().

In my opinion, behavior should be, essentially:

Handler<AsyncResult<T>> succeedingThenComplete() {
  return (ar) -> {/*if ar succeeded, wait until timeout for all remaining checkpoints to be passed.
  otherwise fail.*/}
}

right now it's

inject a testContext
beginning of user's test code {
  since the user called .checkpoint(),
    the injected awaitCompletion will only wait for that one checkpoint to be flagged,
    instead of the .completeNow() from .succeedingThenComplete()'s handler
} end of user's test code
inject awaitCompletion