Skip to content

Custom Fail Message #12

Closed
Closed

Description

@jossjacobo

It would be nice to have a .withFailMessage(...) method to be able to customize failures.

fun Assert<View>.viewIsNotEmpty() {
  assert(actual.childCount).withFailMessage("expected view to not be empty").isGreaterThan(0)
}

Activity

  1. astrdark commented on Apr 3, 2018

    @astrdark

    I'll take this

  2. evant commented on Apr 3, 2018

    @evant
    Collaborator

    Sure! See linked issue for what api I was thinking, let me know if you want to discuss it.

  3. pavelicii commented on Feb 20, 2019

    @pavelicii

    Would it be implemented?

  4. evant commented on Jul 13, 2019

    @evant
    Collaborator

    If anyone's wondering, the reason this hasn't been implemented is there's some design questions around it like:

    • Do we replace the whole message, or do we keep parts of it like [name] ... (value) ex:
    assertThat(person).prop(Person::name).isEqualTo("Alice")
    
    // [name] expected:<["Alice"]> but was:<["Bob"]> (Person(name=Alice)) 
    • Do we need it to be a simple string or lambda, do would it be useful to pass in the actual value?
    assertThat(person, message = "custom message")
    assertThat(person, message = { "custom message" })
    assertThat(person, message = { actual -> "custom message ${show(actual.name)}" })

    So I'm wondering what people's actual use cases are. In other words, what are some examples where you feel you need a custom message over the default one (that can't be solved better by improving the default one or creating a custom assertion)?

  5. geoffreywiseman commented on Sep 3, 2019

    @geoffreywiseman

    For me, I'd say the places where I'm tempted to use this are often places where a custom assertion would work as an alternative. It's usually where the assertion is "in the weeds" and lacks the context necessary to understand the problem.

    For instance, I wrote a test recently that for each plan code in an insurance domain, there should be cash value metadata for a given issue age, plan duration, and gender. By the time I work my way through all those factors, if I discover the plan isn't there, just getting a message that the object is null is not very useful. I want an error message that says that there's no metadata for a given plan code, issue age, plan duration and gender.

    In this case, I ended up finding it simpler to just write classic JUnit assertions with a custom failure message, but I probably could have made a custom assertion. I'm tempted to go back and try just to compare the two paths. A custom assertion feels like more work, but that's probably in part because I've only made one a few times, so it doesn't come naturally to me yet.

  6. franz-see commented on Jan 2, 2020

    @franz-see

    Since assertk was inspired by assertj, might sa well copy what assertj has

    Example of a failing assertion with a description :

     TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
     // failing assertion, remember to call as() before the assertion, not after !
     assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(100);
    

    The error message starts with the given description in [] :

     [check Frodo's age] expected:<100> but was:<33>
    

    https://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html

  7. franz-see commented on Jan 2, 2020

    @franz-see

    Assertion messages usually dont get much love. That's because if your tests pass, then you dont see the value of assertion messages.

    But if your tests fails, that's where you get the value. And it's hard to tell what the error is if you have multiple assertions and you dont have custom assertion messages. Without custom assertion messages, devs starts putting break points on their tests.

  8. evant commented on Jan 2, 2020

    @evant
    Collaborator

    A custom description is already handled by the name param, ex:

    assertThat(frodo.age, name = "check ${frodo.name}'s age").isEqualTo(100)
    expected [check Frodo's age]:<100> but was:<33>
    

    I believe this issue is asking about replacing the message part.

  9. franz-see commented on Jan 2, 2020

    @franz-see

    Great! thanks @evant 😄

    Hope that can be added in the README/docs 😄

  10. agoston commented on Feb 12, 2021

    @agoston

    I was specifically looking into the .withFailMessage(Supplier) version. That has the benefit of not evaluating the assertion until it is printed, which is very handy for more costly messages, DB lookups and such, e.g.:

            assertThat(success).withFailMessage { "DB state: " + repository.findUser(USER_ID) }.hasSize(1)

    For now, I'll keep using assertJ for this use case.

  11. evant commented on Feb 12, 2021

    @evant
    Collaborator

    "DB state: " + repository.findUser(USER_ID)

    hm, would it be useful to allow appending additional state to an assertion? Something like:

    assertThat(success, context = { "DB state: " + repository.findUser(USER_ID)" }).hasSize(1)
    
    // expected [size]:<1> but was:<0>
    //   DB state: User { name = "Tim" }"
    
  12. agoston commented on Feb 13, 2021

    @agoston

    yes, that would help a lot!

    also, another benefit of lambda is that it is evaluated after the assertion, not before. So if assertion changes state, that new state would be printed, not the previous one.

  13. evant commented on Feb 13, 2021

    @evant
    Collaborator

    Cool, created a new issue to track this specifically #344.

  14. locked and limited conversation to collaborators on Apr 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions