Search code examples
scalascalatest

Need advice on how to optimize my Scala tests


I am using ScalaTest for automation. A typical test logical structure is that the test is doing some checks of the application logic and then cleans up. So let's call it a test body part and a test cleanup part. If the test body fails I would like to see it in the test report. If the test body does not fail but the cleanup part fails I also would like to see in the test report that the test ended up with error. So I've come up with the following structure (example is the most simple I can provide):

"Admin" should "be able to create a new team" in{
    val tempTeam = Team("Temp QA Team")
    val attempt=Try{
      When("Admin opens the Teams view")
      TeamsPage.open
      And("creates a new team")
      TeamsPage.createNewTeam(tempTeam)
      Then("this team is shown in the list")
      TeamsPage.isParticularTeamShownInTeamList(tempTeam.name) shouldBe true
    }
    val cleanUp = Try(TeamsPage.cleanUpTeam(tempTeam))
    attempt match{
      case Failure(e) => throw e
      case Success(r) =>{
        if(cleanUp.isFailure) cleanUp.get
        r
      }
    }
  }

Please note here that I need the cleanup part to always execute, not only when the test body part is successful.

It works as I expect but I see two problems:

  1. IntelliJ Idea tells me that cleanUp.get is useless expression. How to write that part in more correct way? I could rewrite it as if(cleanUp.isFailure) throw cleanUp.failed.get, then the IDE would not complain but actually that is a longer way to write the same statement.
  2. The last part of this test code which actually compares results of the test body part and cleanup part and decides what to return looks a bit bloated. Probably you can advice me how to make it more concise and clear?

Solution

  • If I understand what you're trying to do correctly, the answer is flatMap and map as laid out in the documentation for scala.util.Try

    In your case (taking your code as is), you would want

    "Admin" should "be able to create a new team" in{
      val tempTeam = Team("Temp QA Team")
      val attempt=Try{
        When("Admin opens the Teams view")
        TeamsPage.open
        And("creates a new team")
        TeamsPage.createNewTeam(tempTeam)
        Then("this team is shown in the list")
        TeamsPage.isParticularTeamShownInTeamList(tempTeam.name) shouldBe true
      }
      val cleanUp = Try(TeamsPage.cleanUpTeam(tempTeam))
      attempt.flatMap(r => cleanup.map(c => r)).get
    }
    

    This will return the result of attempt, unless it fails, in which case it will throws attempt's exception. It will ignore the successful result of cleanup (as your code did), but if cleanup throws an exception, you'll throw that exception.

    N.B. I didn't actually try this in an IDE, so I can't say if this will address your question #1 about IntelliJ saying that get was a useless expression.