Skip to content

Introduce extension API for expression language evaluation in display names #1154

@DcortezMeleth

Description

@DcortezMeleth

Overview

I have found that it would be useful if you could use argument fields as a part of parametrized test name. Right now, when using just {0} as described in docs, it results in injecting into a test name string in form of ClassName(fieldName1=fieldValue1, fieldName2=fieldValue2, ...). But that doesn't seen readable at all especially then you have a class with more than just few fields. Now I would like to be able to use some semantics as {0.name} or {0}.name to use just name field of class used as test method argument, so I can write test name as follows:

@BeerTest
class BeerConversionServiceTest {

    @Autowired
    private BeerConversionService beerConversionService;

    private static Stream<Arguments> createBeers() {
        return Stream.of(
                Arguments.of(new Beer(...), 25L),
                Arguments.of(new Beer(...), 50L)
        );
    }

    @DisplayName("Get alcohol content of a beer in mg")
    @ParameterizedTest(name = "Alcohol content of {0.name} should be equal to {1}")
    @MethodSource("createBeers")
    void getAlcInMg(Beer beer, long mg) {
        Assertions.assertEquals(beerConversionService.getAlcInMg(beer), mg);
    }

}

This would give users possibility to keep test names simple, yet still descriptive, as they could reference objects passed as arguments and use only parts of them which identifies test cases.

I didn't look into the source code so I cannot tell which approach would be easier to implement but I would guess that {0.name} seems more reasonable.

Deliverables

  • Introduce an SPI (similar to what has been proposed above) and provide a SpEL-based and/or OGNL-based implementation.
    Ensure that display names for @ParameterizedTest and @RepeatedTest can make use of the same facility (see @ParameterizedTest display custom names for arguments #2452).

Activity

marcphilipp

marcphilipp commented on Nov 11, 2017

@marcphilipp
Member

I agree that this would be useful. Implementation-wise it might be a rabbit hole, though. We should probably check for getters first. If there are none, we could try to find a field traversing the class hierarchy upward.

@junit-team/junit-lambda Thoughts?

added this to the 5.x Backlog milestone on Nov 11, 2017
vikaskumar89

vikaskumar89 commented on Nov 17, 2017

@vikaskumar89
Contributor

hi @marcphilipp may i please work on this?

marcphilipp

marcphilipp commented on Nov 17, 2017

@marcphilipp
Member

Sure!

sbrannen

sbrannen commented on Nov 17, 2017

@sbrannen
Member

I agree that this would be useful. Implementation-wise it might be a rabbit hole, though. We should probably check for getters first. If there are none, we could try to find a field traversing the class hierarchy upward.

@junit-team/junit-lambda Thoughts?

  1. accessor method: name()
  2. getter method: getName()
  3. field named name (local and then traversing the hierarchy)
DcortezMeleth

DcortezMeleth commented on Nov 17, 2017

@DcortezMeleth
Author
1. accessor method: name()
2. getter method: getName()
3. field named name (local and then traversing the hierarchy)

Seems like a good idea.

sormuras

sormuras commented on Nov 17, 2017

@sormuras
Member

How about supporting {{ mustache }} notation? We could include this library here https://github.com/spullara/mustache.java

marcphilipp

marcphilipp commented on Nov 17, 2017

@marcphilipp
Member

I was also wondering about that. If we do, it needs to be an extension, though. Moreover, I'm not sure we need everything mustache has to offer. 🤔

DcortezMeleth

DcortezMeleth commented on Nov 17, 2017

@DcortezMeleth
Author

Mustache may be a nice addition but I agree with Mark that if it's going to be used it should be provided as some kind of extension because it will be used by rather small amount of users.

But will we need anything apart of this simple usecase? If not, additional dependecy seems a bit unnecessary.

marcphilipp

marcphilipp commented on Nov 17, 2017

@marcphilipp
Member

Do we want to support things like {0.manufacturer.owner.name}?

sbrannen

sbrannen commented on Nov 18, 2017

@sbrannen
Member

Based on the discussions here, I think it's already starting to get a bit out of hand.

As soon as we support one level of expressions, people will want more, and then they'll want additional features that the JUnit Team should not be implementing (due to scope).

So, in order to avoid feature creep, my proposal is to go back to the original plan (from the JUnit Lambda prototype phase) to add an extension for plugging in a custom expression language.

See also:

In summary, I believe it would be better to design a new extension API that receives the String displayName and a Map<String,Object> expressionContextMap and then allow people to pick between Mustache, SpEL, etc.

sbrannen

sbrannen commented on Nov 18, 2017

@sbrannen
Member

For example...

  • With Mustache, it might look like "Owner: {0.manufacturer.owner.name}".
  • With SpEL (from Spring), it might look like "Owner: #{#0.manufacturer.owner.name}" or "Owner: #{#beer.manufacturer.owner.name}".

47 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @xenoterracide@sbrannen@marcphilipp@jean-andre-gauthier@sormuras

    Issue actions

      Introduce extension API for expression language evaluation in display names · Issue #1154 · junit-team/junit-framework