Search code examples
scalascalatest

Scala test eventually configuration for all implementations?


I have many many tests that runs with asynchronous code in scala, I am working with scala concurrent eventually. This helps me to know when given a certain asynchronous event happens I can expect certain values.

But eventually has a timeout that can be overwritten for each test so it does not crash expecting for a value that is not there yet...

I would like to change this timeout for all the implementations of eventually with one configuration change for all the tests.

In terms of code I do the following:

class AsyncCharacterTest extends WordSpec
  with Matchers
  with Eventually
  with BeforeAndAfterAll
  with ResponseAssertions {
  "Should provide the character from that where just created" should {
    val character = Character(name = "juan", age = 32)
    service.createIt(character)
    eventually(timeout(2.seconds)){ 
      responseAs[Character] should be character
    }
  }
}

I would like not to have to write this timeout(2.seconds) for each test... I would like to have a configuration for all the tests with the chance to override this timeout for specific cases.

Is this possible with scala concurrent eventually? this would help me to write more DRY code.

Doing something like

Eventually.default.timeout = 2.seconds

And then this is working for all the tests at the same time with 2 seconds by default.


Solution

  • Essentially, what you currently do by eventually(timeout(...))) is provide an explicit value to an implicit parameter.

    One simple way to achieve what you want would be to do the following:

    1. Remove all the explicit timeout() from `eventually call.

    2. Create a trait to contain a desired default value for the timeout as an implicit value:

       trait EventuallyTimeout {
        implicit val patienceConfig: PatienceConfig = PatienceConfig(timeout = ..., interval = ...)
      

      }

    3. Mix this trait in into all of your tests:

       class AsyncCharacterTest extends WordSpec extends EventuallyTimeout extends ...
      

    Full example:

    // likely in a different file
    trait EventuallyTimeout {
        implicit val patienceConfig: PatienceConfig = PatienceConfig(timeout = ..., interval = ...)
    }
    
    class AsyncCharacterTest extends WordSpec
      with Matchers
      with Eventually
      with BeforeAndAfterAll
      with ResponseAssertions 
      with EventuallyTimeout {
          "Should provide the character from that where just created" should {
            val character = Character(name = "juan", age = 32)
            service.createIt(character)
            eventually { 
              responseAs[Character] should be character
            }
          }
    }
    

    For more details, refer to Eventually docs and implicit.

    Finallly, on a side note, eventually is mostly intended for integration testing. You might want to consider using different mechanisms, such as:

    1. ScalaFutures trait + whenReady method - similar to eventually approach.
    2. Async* spec counterparts (ie. AsyncFunSpec, AsyncWordSpec, etc.).