- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Always declare Unit return type for testng @Test methods
Tue, 2011-06-28, 10:24
I'm running testng tests (see http://testng.org). Here's a piece of advice that took me quite some time to figure out:
ALWAYS declare your test methods to return Unit, DON'T let the return type be inferred by the scala compiler, BECAUSE testng executes only methods returning void / Unit. Look at this simplified example:
import org.testng.annotations.Test
class Tests {
def helper = 1
@Test
def willNeverRun = {
helper
}
@Test
def thisOneWillRun : Unit = {
helper
}
}
In my tests, I was using org.fest.assertions.Assertions.assertThat and was wondering why "assertThat(string1) isEqualTo string2" would not execute as test (returns non-Unit) while "assertThat(boolean1) isTrue" would execute as test (returns Unit).
Cheers
Georg
ALWAYS declare your test methods to return Unit, DON'T let the return type be inferred by the scala compiler, BECAUSE testng executes only methods returning void / Unit. Look at this simplified example:
import org.testng.annotations.Test
class Tests {
def helper = 1
@Test
def willNeverRun = {
helper
}
@Test
def thisOneWillRun : Unit = {
helper
}
}
In my tests, I was using org.fest.assertions.Assertions.assertThat and was wondering why "assertThat(string1) isEqualTo string2" would not execute as test (returns non-Unit) while "assertThat(boolean1) isTrue" would execute as test (returns Unit).
Cheers
Georg
Tue, 2011-06-28, 17:27
#2
Re: Re: Always declare Unit return type for testng @Test method
On 28 June 2011 16:53, Lars Hupel <hupel@in.tum.de> wrote:
Hi Georg,
you may also specify your functions like
def foo {
3
}
that is, without '=' after the parameter list. This will always give you
'Unit' as the return type.
Lars
I would strongly advise against that!
In most cases, you can leave out the surrounding braces for a method implemented as a single expression, the alternative syntax doesn't allow for that possibility - and so is inconsistent.
I also find it's a very worthy rule-of-thumb to avoid side effects, so it helps to make things explicit when you're doing so:
def foo: Unit = ...
The `: Unit` then serves as a visible warning.
p.s. I've learned from experience that you can also avoid a lot of potential confusion (especially in more complicated examples) by being very clear on the distinction between methods and functions.
--
Kevin Wright
gtalk / msn : kev.lee.wright@gmail.comkev.lee.wright@gmail.commail: kevin.wright@scalatechnology.com
vibe / skype: kev.lee.wrightquora: http://www.quora.com/Kevin-Wright
twitter: @thecoda
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Tue, 2011-06-28, 17:47
#3
Re: Re: Always declare Unit return type for testng @Test method
By the same argument, the visible lack of '=' in
def foo {
...
}
is a clear visible warning of side effect,
Not disagreeing with you, just making an observation!
On Tue, Jun 28, 2011 at 5:14 PM, Kevin Wright wrote:
> The `: Unit` then serves as a visible warning.
Tue, 2011-06-28, 17:57
#4
Re: Re: Always declare Unit return type for testng @Test method
On 28 June 2011 17:40, Alec Zorab <aleczorab@googlemail.com> wrote:
By the same argument, the visible lack of '=' in
def foo {
...
}
is a clear visible warning of side effect,
Not disagreeing with you, just making an observation!
I'm not convinced that the *absence* of a single easily-overlooked character can be classed as a "clear visible warning".
On Tue, Jun 28, 2011 at 5:14 PM, Kevin Wright <kev.lee.wright@gmail.com> wrote:
> The `: Unit` then serves as a visible warning.
Tue, 2011-06-28, 19:47
#5
Re: Re: Always declare Unit return type for testng @Test method
I've used the "def foo() {...}" convention to indicate a procedure since since day 1 (my day 1, when I first started experimenting with Scala :-) ), and I've found that one becomes used to it; whenever I work on a method, my mind just does an automatic check to see if there is an "=" there. I find it's rare that I get errors of this nature.
That being said, it would be neat if the editors (I use IDEA) highlighted functions and procedures differently in some way.
Cheers,Ken
That being said, it would be neat if the editors (I use IDEA) highlighted functions and procedures differently in some way.
Cheers,Ken
Tue, 2011-06-28, 19:57
#6
Re: Always declare Unit return type for testng @Test methods
> I would strongly advise against that!
>
> In most cases, you can leave out the surrounding braces for a method
> implemented as a single expression, the alternative syntax doesn't allow for
> that possibility - and so is inconsistent.
>
> I also find it's a very worthy rule-of-thumb to avoid side effects, so it
> helps to make things explicit when you're doing so:
>
> def foo: Unit = ...
>
> The `: Unit` then serves as a visible warning.
You certainly have a point there. I just wanted to throw it in because
the original post used { } for just a single expression.
> p.s. I've learned from experience that you can also avoid a lot of potential
> confusion (especially in more complicated examples) by being very clear on
> the distinction between methods and functions.
Of course, sloppy me :)
Tue, 2011-06-28, 20:17
#7
Re: Re: Always declare Unit return type for testng @Test method
On 28 June 2011 19:32, Ken McDonald <ykkenmcd@gmail.com> wrote:
I've used the "def foo() {...}" convention to indicate a procedure since since day 1 (my day 1, when I first started experimenting with Scala :-) ), and I've found that one becomes used to it; whenever I work on a method, my mind just does an automatic check to see if there is an "=" there. I find it's rare that I get errors of this nature.
That being said, it would be neat if the editors (I use IDEA) highlighted functions and procedures differently in some way.
Cheers,Ken
It's a subtle problem.
When coming from Java, a lot of your early code will tend to be side-effecting. It's hardly surprising, as this is how much of Java works, void returns are the norm. For example, calling a method on a (mutable) collection to add an element to it and disregarding the return value.
With a codebase of this nature, it becomes normal to assume Unit returns and learning to recognise the = symbol as suggesting that there *is* a significant return.
With time, you'll find your code migrating more and more to use pure functions, immutable datatypes, etc, etc. In this case, Unit return values will be very much the exception. ... and that's when it becomes dangerous! If you're no longer used to looking for, or expecting, these methods that are pure side effect, then it's oh-so-easy to miss the absence of the `=` sign. whereas an explicit `: Unit` will stand out like a flashing red light (especially if much of your code allows return types to be inferred)
It's for this reason that I teach people to use an explicit return in these scenarios. Not because it'll make all that much difference for anyone first coming to Scala, but because I know - from personal experience - that it'll help further down the line.
--
Kevin Wright
gtalk / msn : kev.lee.wright@gmail.comkev.lee.wright@gmail.commail: kevin.wright@scalatechnology.com
vibe / skype: kev.lee.wrightquora: http://www.quora.com/Kevin-Wright
twitter: @thecoda
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Tue, 2011-06-28, 21:07
#8
Re: Always declare Unit return type for testng @Test methods
Thanks all for your thoghts on the topic! Just to clarify, most of my
test methods have more than one line (so the example was poorly chosen
in this respect). For my testng tests, I think I will stick to the
@Test
def testit: Unit = { ... }
notation, although I confess I was temped to adopt the
@Test
def testit { ... }
notation. Still, with the latter it's all too easy to accidentially
put an "=" there, and boom - testng might not execute the test.
Additionally I will raise an issue with testng that they support test
methods that return non-void.
As for the side-effect discussion here, I would think that a test
method like
@Test
def testit : Unit = {
assert( myImmutableObject.someMethod() == "expected result" )
}
can be considered to have no side effect although it does not return a
value!
Georg
Tue, 2011-06-28, 22:07
#9
Re: Re: Always declare Unit return type for testng @Test method
On Tue, Jun 28, 2011 at 12:58 PM, g-diet-rich <u.g.dietrich@googlemail.com> wrote:
Note that this will have to be an option since changing this might break existing tests.
Feel free to follow-up on the testng-users list, I'll see you there.
-- Cédric
Additionally I will raise an issue with testng that they support test
methods that return non-void.
Note that this will have to be an option since changing this might break existing tests.
Feel free to follow-up on the testng-users list, I'll see you there.
-- Cédric
Tue, 2011-06-28, 23:37
#10
Re: Re: Always declare Unit return type for testng @Test method
Hi Georg,
On Tue, Jun 28, 2011 at 12:58 PM, g-diet-rich
wrote:
> Thanks all for your thoghts on the topic! Just to clarify, most of my
> test methods have more than one line (so the example was poorly chosen
> in this respect). For my testng tests, I think I will stick to the
>
> @Test
> def testit: Unit = { ... }
>
> notation, although I confess I was temped to adopt the
>
> @Test
> def testit { ... }
>
> notation. Still, with the latter it's all too easy to accidentially
> put an "=" there, and boom - testng might not execute the test.
> Additionally I will raise an issue with testng that they support test
> methods that return non-void.
>
I think there's nothing wrong with doing it that way except of the
gotcha with testng. I recommend doing that style in a ScalaTest Suite.
My reason is:
Note also that two test methods, testFriendly and testComposable, are
declared as parameterless methods even though they have a side effect.
In production code you would normally declare these as empty-paren
methods, and call them with empty parentheses, to make it more obvious
to readers of the code that they have a side effect. Whether or not a
test method has a side effect, however, is a less important
distinction than it is for methods in production code. Moreover, test
methods are not normally invoked directly by client code, but rather
through reflection by running the Suite that contains them, so a lack
of parentheses on an invocation of a side-effecting test method would
not normally appear in any client code. Given the empty parentheses do
not add much value in the test methods case, the recommended style is
to simply always leave them off
This is from the Scaladoc for trait Suite:
http://www.scalatest.org/scaladoc-1.6.1/#org.scalatest.Suite
One other thing testng could possibly do differently that would help
you but wouldn't break existing tests is report some kind of error
when it discovers a non-void method annotated with @Test.
Bill
> As for the side-effect discussion here, I would think that a test
> method like
>
> @Test
> def testit : Unit = {
> assert( myImmutableObject.someMethod() == "expected result" )
> }
>
> can be considered to have no side effect although it does not return a
> value!
>
> Georg
>
Wed, 2011-06-29, 01:07
#11
Re: Re: Always declare Unit return type for testng @Test method
On Tue, Jun 28, 2011 at 3:31 PM, Bill Venners <bill@artima.com> wrote:
TestNG will issue a warning about this if verbose >= 3.
-- Cédric
One other thing testng could possibly do differently that would help
you but wouldn't break existing tests is report some kind of error
when it discovers a non-void method annotated with @Test.
TestNG will issue a warning about this if verbose >= 3.
-- Cédric
Wed, 2011-06-29, 01:17
#12
Re: Re: Always declare Unit return type for testng @Test method
On 29/06/11 05:58, g-diet-rich wrote:
> Thanks all for your thoghts on the topic! Just to clarify, most of my
> test methods have more than one line (so the example was poorly chosen
> in this respect). For my testng tests, I think I will stick to the
>
> @Test
> def testit: Unit = { ... }
>
> notation, although I confess I was temped to adopt the
>
> @Test
> def testit { ... }
>
> notation. Still, with the latter it's all too easy to accidentially
> put an "=" there, and boom - testng might not execute the test.
> Additionally I will raise an issue with testng that they support test
> methods that return non-void.
>
> As for the side-effect discussion here, I would think that a test
> method like
>
> @Test
> def testit : Unit = {
> assert( myImmutableObject.someMethod() == "expected result" )
> }
>
> can be considered to have no side effect although it does not return a
> value!
>
> Georg
Assert is a side-effect.
Any function returning type Unit that cannot be replaced with () and
have equivalent program outcome is telling whoppers in the type -- that
is, side-effecting.
There exists f such that
f(testit) =/= f(())
∴ testit is side-effecting
Wed, 2011-06-29, 02:57
#13
Re: Re: Always declare Unit return type for testng @Test method
Hi Tony,
On Tue, Jun 28, 2011 at 5:12 PM, Tony Morris wrote:
> Assert is a side-effect.
>
> Any function returning type Unit that cannot be replaced with () and
> have equivalent program outcome is telling whoppers in the type -- that
> is, side-effecting.
>
> There exists f such that
> f(testit) =/= f(())
>
> ∴ testit is side-effecting
>
I consider a thrown exception to be a side effect, but on the JVM any
method could throw an exception. You can get an OutOfMemoryError at
any time, for example, or some API call you invoke could blow up with
NullPointerException and you do too, etc. So saying any method that
could throw an exception is side-effecting, that would mean no
functions in Scala can be side-effect free, which isn't what we mean
by side effects in Scala. I think we mean if in the normal course of
non-exceptional behavior there are no exceptions thrown (and it has no
other side effects), then it is side effect free. A test designed to
fail with an exception sounds like a side-effecting function by
nature, though even that could be debated because most tests don't
fail most of the time in practice. It is actually usually supposed to
be quite exceptional for a test to fail over the lifetime of the test.
Regardless, some tests have non-exception side effects like reading
and writing data from files. And in all those cases my recommendation
was in test methods you can leave off the () even though the methods
may have side-effects, because no one usually calls those methods.
Bill
----
Bill Venners
Artima, Inc.
http://www.artima.com
Wed, 2011-06-29, 03:27
#14
Re: Re: Always declare Unit return type for testng @Test method
On 29/06/11 11:47, Bill Venners wrote:
> Hi Tony,
>
> On Tue, Jun 28, 2011 at 5:12 PM, Tony Morris wrote:
>> Assert is a side-effect.
>>
>> Any function returning type Unit that cannot be replaced with () and
>> have equivalent program outcome is telling whoppers in the type -- that
>> is, side-effecting.
>>
>> There exists f such that
>> f(testit) =/= f(())
>>
>> ∴ testit is side-effecting
>>
> I consider a thrown exception to be a side effect, but on the JVM any
> method could throw an exception. You can get an OutOfMemoryError at
> any time, for example, or some API call you invoke could blow up with
> NullPointerException and you do too, etc.
This is a consequence of being turing-complete. The method may also spin
forever. This is aside from whether or not the function is
side-effecting. The formula I gave above is fool-proof.
> So saying any method that
> could throw an exception is side-effecting,
... which I didn't say. I said the function is side-effecting by the
definition of what it means to be side-effecting. It happens to achieve
this by throwing an exception, which is well documented to be a
side-effect (Types and Programming Languages -- Benjamin Pierce).
> that would mean no
> functions in Scala can be side-effect free
No actually, it wouldn't. It simply means that the system of logic we
are using (in this case, intuitionistic logic) is inconsistent. This is
true for any turing-complete language, which as it happens, scala's type
system itself happens to satisfy (ever seen a type-checker crash?).
Proof
http://apocalisp.wordpress.com/2011/01/13/simple-ski-combinator-calculus...
> , which isn't what we mean
> by side effects in Scala.
There is no "side-effects in Scala", which is distinguishable from just
"side-effects."
Again, the fool-proof method is simply, if replacing the expression with
its value in any potential occurrence results in observable different
program outcome, then the expression side-effects. Exceptions, whatever,
it doesn't matter -- the expression side-effects.
In this case, the value is trivial (Unit), so you can test using its
only possible value ().
> I think we mean if in the normal course of
> non-exceptional behavior there are no exceptions thrown (and it has no
> other side effects), then it is side effect free. A test designed to
> fail with an exception sounds like a side-effecting function by
> nature, though even that could be debated because most tests don't
> fail most of the time in practice. It is actually usually supposed to
> be quite exceptional for a test to fail over the lifetime of the test.
I think you are confusing termination and side-effects, although they
are closely related.
> Regardless, some tests have non-exception side effects like reading
> and writing data from files. And in all those cases my recommendation
> was in test methods you can leave off the () even though the methods
> may have side-effects, because no one usually calls those methods.
I am very much against this awful effect-tracking system/convention (no,
it is not better than nothing), but this opinion is aside.
I think it is important that there exist at least two people who are of
the false belief that the expression is not a side-effect, when it most
definitely is -- how does this affect our programs? Beware.
> Bill
> ----
> Bill Venners
> Artima, Inc.
> http://www.artima.com
Hi Georg,
you may also specify your functions like
def foo {
3
}
that is, without '=' after the parameter list. This will always give you
'Unit' as the return type.
Lars