Configuration object for asynchronous constructs, such as those provided by traits Eventually
and
AsyncAssertions
.
Configuration object for asynchronous constructs, such as those provided by traits Eventually
and
AsyncAssertions
.
The default values for the parameters are:
Configuration Parameter | Default Value |
---|---|
timeout
|
scaled(150 milliseconds)
|
interval
|
scaled(15 milliseconds)
|
the maximum amount of time to wait for an asynchronous operation to complete before giving up and throwing
TestFailedException
.
the amount of time to sleep between each check of the status of an asynchronous operation when polling
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
The by-name parameter "succeeds" if it returns a result. It "fails" if it throws any exception that
would normally cause a test to fail. (These are any exceptions except TestPendingException
and
Error
s listed in the
Treatment of java.lang.Error
s section of the
documentation of trait Suite
.)
The maximum amount of time in milliseconds to tolerate unsuccessful attempts before giving up is configured by the timeout
field of
the PatienceConfig
passed implicitly as the last parameter.
The interval to sleep between attempts is configured by the interval
field of
the PatienceConfig
passed implicitly as the last parameter.
the by-name parameter to repeatedly invoke
the PatienceConfig
object containing the timeout
and
interval
parameters
the result of invoking the fun
by-name parameter, the first time it succeeds
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
The by-name parameter "succeeds" if it returns a result. It "fails" if it throws any exception that
would normally cause a test to fail. (These are any exceptions except TestPendingException
and
Error
s listed in the
Treatment of java.lang.Error
s section of the
documentation of trait Suite
.)
The maximum amount of time in milliseconds to tolerate unsuccessful attempts before giving up is configured by the timeout
field of
the PatienceConfig
passed implicitly as the last parameter.
The interval to sleep between attempts is configured by the value contained in the passed
interval
parameter.
the Interval
configuration parameter
the by-name parameter to repeatedly invoke
the PatienceConfig
object containing the (used) timeout
and
(unused) interval
parameters
the result of invoking the fun
by-name parameter, the first time it succeeds
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
The by-name parameter "succeeds" if it returns a result. It "fails" if it throws any exception that
would normally cause a test to fail. (These are any exceptions except TestPendingException
and
Error
s listed in the
Treatment of java.lang.Error
s section of the
documentation of trait Suite
.)
The maximum amount of time in milliseconds to tolerate unsuccessful attempts before giving up and throwing
TestFailedException
is configured by the value contained in the passed
timeout
parameter.
The interval to sleep between attempts is configured by the interval
field of
the PatienceConfig
passed implicitly as the last parameter.
the Timeout
configuration parameter
the by-name parameter to repeatedly invoke
the PatienceConfig
object containing the (unused) timeout
and
(used) interval
parameters
the result of invoking the fun
by-name parameter, the first time it succeeds
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
Invokes the passed by-name parameter repeatedly until it either succeeds, or a configured maximum amount of time has passed, sleeping a configured interval between attempts.
The by-name parameter "succeeds" if it returns a result. It "fails" if it throws any exception that
would normally cause a test to fail. (These are any exceptions except TestPendingException
and
Error
s listed in the
Treatment of java.lang.Error
s section of the
documentation of trait Suite
.)
The maximum amount of time in milliseconds to tolerate unsuccessful attempts before giving up and throwing
TestFailedException
is configured by the value contained in the passed
timeout
parameter.
The interval to sleep between attempts is configured by the value contained in the passed
interval
parameter.
the Timeout
configuration parameter
the Interval
configuration parameter
the by-name parameter to repeatedly invoke
the result of invoking the fun
by-name parameter, the first time it succeeds
Returns an Interval
configuration parameter containing the passed value, which
specifies the amount of time to sleep after a retry.
Returns an Interval
configuration parameter containing the passed value, which
specifies the amount of time to sleep after a retry.
Implicit PatienceConfig
value providing default configuration values.
Implicit PatienceConfig
value providing default configuration values.
To change the default configuration, override or hide this def
with another implicit
PatienceConfig
containing your desired default configuration values.
Scales the passed Span
by the Double
factor returned
by spanScaleFactor
.
Scales the passed Span
by the Double
factor returned
by spanScaleFactor
.
The Span
is scaled by invoking its scaledBy
method,
thus this method has the same behavior:
The value returned by spanScaleFactor
can be any positive number or zero,
including a fractional number. A number greater than one will scale the Span
up to a larger value. A fractional number will scale it down to a smaller value. A
factor of 1.0 will cause the exact same Span
to be returned. A
factor of zero will cause Span.ZeroLength
to be returned.
If overflow occurs, Span.Max
will be returned. If underflow occurs,
Span.ZeroLength
will be returned.
IllegalArgumentException
if the value returned from spanScaleFactor
is less than zero
The factor by which the scaled
method will scale Span
s.
The factor by which the scaled
method will scale Span
s.
The default implementation of this method will return the span scale factor that
was specified for the run, or 1.0 if no factor was specified. For example, you can specify a span scale factor when invoking ScalaTest
via the command line by passing a -F
argument to Runner
.
Returns a Timeout
configuration parameter containing the passed value, which
specifies the maximum amount to wait for an asynchronous operation to complete.
Returns a Timeout
configuration parameter containing the passed value, which
specifies the maximum amount to wait for an asynchronous operation to complete.
Trait that provides the
eventually
construct, which periodically retries executing a passed by-name parameter, until it either succeeds or the configured timeout has been surpassed.The by-name parameter "succeeds" if it returns a result. It "fails" if it throws any exception that would normally cause a test to fail. (These are any exceptions except
TestPendingException
andError
s listed in the Treatment ofjava.lang.Error
s section of the documentation of traitSuite
.)For example, the following invocation of
eventually
would succeed (not throw an exception):However, because the default timeout is 150 milliseconds, the following invocation of
eventually
would ultimately produce aTestFailedDueToTimeoutException
:Assuming the default configuration parameters, a
timeout
of 150 milliseconds and aninterval
of 15 milliseconds, were passed implicitly toeventually
, the detail message of the thrownTestFailedDueToTimeoutException
would look like:The code passed to eventually never returned normally. Attempted 2 times over 166.682 milliseconds. Last failure message: 2 was not equal to 110.
The cause of the thrown
TestFailedDueToTimeoutException
will be the exception most recently thrown by the block of code passed to eventually. (In the previous example, the cause would be theTestFailedException
with the detail message2 was not equal to 100
.)Configuration of
eventually
The
eventually
methods of this trait can be flexibly configured. The two configuration parameters foreventually
along with their default values and meanings are described in the following table:timeout
scaled(150 milliseconds)
TestFailedDueToTimeoutException
interval
scaled(15 milliseconds)
The default values of both timeout and interval are passed to the
scaled
method, inherited fromScaledTimeSpans
, so that the defaults can be scaled up or down together with other scaled time spans. See the documentation for traitScaledTimeSpans
for more information.The
eventually
methods of traitEventually
each take aPatienceConfig
object as an implicit parameter. This object provides values for the two configuration parameters. (These configuration parameters are called "patience" because they determine how patient tests will be with asynchronous operations: how long they will tolerate failures before giving up and how long they will wait before checking again after a failure.) TraitEventually
provides an implicitval
namedpatienceConfig
with each configuration parameter set to its default value. If you want to set one or more configuration parameters to a different value for all invocations ofeventually
in a suite you can override this val (or hide it, for example, if you are importing the members of theEventually
companion object rather than mixing in the trait). For example, if you always want the defaulttimeout
to be 2 seconds and the defaultinterval
to be 5 milliseconds, you can overridepatienceConfig
, like this:Or, hide it by declaring a variable of the same name in whatever scope you want the changed values to be in effect:
Passing your new default values to
scaled
is optional, but a good idea because it allows them to be easily scaled if run on a slower or faster system.In addition to taking a
PatienceConfig
object as an implicit parameter, theeventually
methods of traitEventually
include overloaded forms that take one or twoPatienceConfigParam
objects that you can use to override the values provided by the implicitPatienceConfig
for a singleeventually
invocation. For example, if you want to settimeout
to 5 seconds for just one particulareventually
invocation, you can do so like this:This invocation of
eventually
will use 5 seconds for thetimeout
and whatever value is specified by the implicitly passedPatienceConfig
object for theinterval
configuration parameter. If you want to set both configuration parameters in this way, just list them separated by commas:You can also import or mix in the members of
SpanSugar
if you want a more concise DSL for expressing time spans:Note that ScalaTest will not scale any time span that is not explicitly passed to
scaled
to make the meaning of the code as obvious as possible. Thus if you ask for "timeout(5 seconds)
" you will get exactly that: a timeout of five seconds. If you want such explicitly given values to be scaled, you must pass them toscale
explicitly like this:The previous code says more clearly that the timeout will be five seconds, unless scaled higher or lower by the
scaled
method.Simple backoff algorithm
The
eventually
methods employ a very simple backoff algorithm to try and maximize the speed of tests. If an asynchronous operation completes quickly, a smaller interval will yield a faster test. But if an asynchronous operation takes a while, a small interval will keep the CPU busy repeatedly checking and rechecking a not-ready operation, to some extent taking CPU cycles away from other processes that could proceed. To strike the right balance between these design tradeoffs, theeventually
methods will check more frequently during the initial interval.Rather than sleeping an entire interval if the initial attempt fails,
eventually
will only sleep 1/10 of the configured interval. It will continue sleeping only 1/10 of the configured interval until the configured interval has passed, after which it sleeps the configured interval between attempts. Here's an example in which the timeout is set equal to the interval:Even though this call to
eventually
will time out after only one interval, approximately, the error message will likely report that more than one (and less than ten) attempts were made:The code passed to eventually never returned normally. Attempted 6 times over 100.485 milliseconds. Last failure message: 6 was not equal to 110.
Note that if the initial attempt takes longer than the configured interval to complete,
eventually
will never sleep for a 1/10 interval. You can observe this behavior in the second example above in which the first statement in the block of code passed toeventually
wasThread.sleep(50)
.Usage note:
Eventually
intended primarily for integration testingAlthough the default timeouts of trait
Eventually
are tuned for unit testing, the use ofEventually
in unit tests is a choice you should question. Usually during unit testing you'll want to mock out subsystems that would requireEventually
, such as network services with varying and unpredictable response times. This will allow your unit tests to run as fast as possible while still testing the focused bits of behavior they are designed to test.Nevertheless, because sometimes it will make sense to use
Eventually
in unit tests (and because it is destined to happen anyway even when it isn't the best choice),Eventually
by default uses timeouts tuned for unit tests: Calls toeventually
are more likely to succeed on fast development machines, and if a call does time out, it will do so quickly so the unit tests can move on.When you are using
Eventually
for integration testing, therefore, the default timeout and interval may be too small. A good way to override them is by mixing in traitIntegrationPatience
or a similar trait of your own making. Here's an example:Trait
IntegrationPatience
increases the default timeout from 150 milliseconds to 15 seconds, the default interval from 15 milliseconds to 150 milliseconds. If need be, you can do fine tuning of the timeout and interval by specifying a time span scale factor when you run your tests.