Skip to content

testing: add M.Cleanup #42161

Description

@matttproud

This is a feature request/proposal for testing.M. I was doing a Readability Review today of user code. The code for one reason or another was using a custom main entrypoint. I noticed how bare the support in testing.M is for users to report and handle setup/teardown failures as well as conduct cleanups. The setup, execution, and teardown of the custom test main needed to do both of these tasks. It dawned on me that there no advice is given in the documentation about where setup error messages should go and how to correctly abort (e.g., what exit value).

I would like to propose that for similar reasons of testing.T having (*testing.T).Cleanup and (*testing.T).Fatal, testing.M should have the same.

Between the two of them, the cleanup is less important. But how to report errors and setup failures looks very relevant.

For instance, if a test main fails, should the user call log.Fatal or one of its variants, hand emit to stderr or stdout? I have seen the whole zoo of behavior before. Is any non-zero exit value OK or only some? I get that custom test mains are an advanced feature and should be seldom used, but it seems potentially like we are not providing the users an adequately documented journey. Maybe this is intentional (e.g., Go tests to support custom test harness and executor requirement contracts)? It does deserve some Schrift at the very least.

Activity

  1. added this to the Proposal milestone on Oct 23, 2020
  2. ianlancetaylor commented on Oct 23, 2020

    @ianlancetaylor
    Contributor

    It seems to me that testing.M.Cleanup can be implemented simply using defer. This isn't true for testing.T.Cleanup, because of parallel subtests, which can continue to run after the test function completes. So I don't see a strong argument for adding testing.M.Cleanup.

  3. matttproud commented on Oct 23, 2020

    @matttproud
    ContributorAuthor
  4. rsc commented on Jul 14, 2021

    @rsc
    Contributor

    It sounds like we don't need to worry about an M.Cleanup until/unless we have M.Fatal etc.
    And I don't know why we would have M.Fatal - is that a separate proposal?
    M is intentionally low-level. It's not supposed to be something with a rich API.

  5. changed the title [-]Proposal: Give testing.M both a Cleanup and Failure Logging Function[/-] [+]testing: add M.Cleanup[/+] on Jul 14, 2021
  6. matttproud commented on Jul 14, 2021

    @matttproud
    ContributorAuthor
  7. rsc commented on Jul 14, 2021

    @rsc
    Contributor

    It's certainly easy to add a sentence or two to testing.M.

  8. rsc commented on Jul 14, 2021

    @rsc
    Contributor

    Based on the discussion above, this proposal seems like a likely decline.
    — rsc for the proposal review group

  9. gopherbot commented on Jul 14, 2021

    @gopherbot
    Contributor

    Change https://golang.org/cl/334649 mentions this issue: testing: clarify in docs that TestMain is advanced

  10. rsc commented on Jul 21, 2021

    @rsc
    Contributor

    No change in consensus, so declined.
    — rsc for the proposal review group

  11. AndrewDK commented on Mar 24, 2022

    @AndrewDK

    Reviving an old issue, the use case here is that deferred functions that are called in TestMain do not run if there's a panic in m.Run, even if there's a deferred recover on the stack in TestMain. Any processes started in TestMain don't get cleaned up when the test exits in this case.

  12. moved this to Declined in Proposalson Aug 10, 2022
  13. sunny-b commented on Oct 14, 2022

    @sunny-b

    Adding my hat to this. The documentation on testing.M is a bit confusing and contradictory to being able to cleanup after functions. The main example is that m.Run returns an exit code that is meant to be used in os.Exit.

    It even says so in the documentation

    However, were you to actually use os.Exit, it would bypass any defer statements you made in order to cleanup.

    The best way I found to get around this was to only call os.Exit if the code was not a successful exit (i.e. not 0). But that's a bit wonky IMO. The documentation should probably be a bit more clear about that.

    retCode := m.Run()
    
    if retCode != 0 {
      os.Exit(retCode)
    }
  14. removed this from Proposalson Oct 19, 2022
  15. locked and limited conversation to collaborators on Oct 14, 2023
  16. added a commit that references this issue on Apr 29, 2024
    0941dbc
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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions