On Tuesday 13 October 2009, Bill Venners wrote:
> Josh Cough created a class you can use to get it to work. We are still
> negotiating whether to add this class to ScalaTest or sbt, banging the
> dependency back and forth like playing ping pong.
We agree that It is not good for sbt or ScalaTest to have to depend on
the other. So, I propose creating a separate test framework
interface. The purpose is to make it easy for for tools to support
running tests from any of the three Scala testing frameworks. The
needs of sbt are I think basic and framework agnostic. It needs the
interface to provide the ability to:
- send output to $logger (more later)
- run test $classname
- return the result of the test
The interface would be pure Java so that calling a test framework
through this interface would be binary compatible across Scala
versions and test framework versions. Then, sbt running Scala 2.7.5
can run ScalaTest 1.0 compiled against 2.7.5 or 2.8.0-whatever or
ScalaTest 1.1 against 2.8.1.
To be more specific, sbt needs the interface to provide:
- the framework name, i.e. "ScalaTest", "specs", or "ScalaCheck"
- the type name that identifies a test ("org.scalatest.Suite",
org.specs.Specification, or "org.scalacheck.Properties") and whether a
test is a class (ScalaTest) or a module (specs, ScalaCheck)
- a test runner that
+ logs output through a basic Logger interface ( def error(msg:
String), def info(msg: String), ...)
+ runs a test with a given name using the provided ClassLoader and
reports success, failure, skipped, or error
+ perhaps extra options to pass to the framework as a Seq[String]
This is very much intended to be a lightweight, common view of the
frameworks. It would solve an important problem for sbt and I hope
would not be too much of a burden on framework authors. Each
framework would have to:
- introduce a compile-time dependency on a small Java jar defining a
simple interface to the frameworks (wouldn't be necessary at runtime
unless using the interface)
- implement the interface
A sample, minimal interface is attached based on some of sbt's current
code. (meant to be illustrative- I didn't actually compile it)
Thanks for reading!
-Mark
If something like this gets implemented by the test frameworks, I think I can
finally have sbt separate the version of Scala doing the compiling from the
version running sbt.
As for Java interfaces as a general technique, it is indeed how I will be
interfacing between the different components of sbt running under different
versions of Scala.
I will take care of ScalaTest 1.0 support in sbt.
-Mark
This is certainly a great idea. I'll implement it in ScalaCheck 1.7-SNAPSHOT.
How should we coordinate the work around the common interfaces, should
we put up a new
tiny project to handle it, where we all (Mark, Bill, Erik, Rickard)
can commit changes?
Or do you have any other suggestions?
Regards,
Rickard
Quoting Mark Harrah <dmha...@gmail.com>:
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to the Google
> Groups "simple-build-tool" group.
> To post to this group, send email to simple-b...@googlegroups.com
> To unsubscribe from this group, send email to
> simple-build-t...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/simple-build-tool?hl=en
> -~----------~----~----~----~------~----~------~--~---
>
>
> Hi,
>
> This is certainly a great idea. I'll implement it in ScalaCheck 1.7-SNAPSHOT.
>
> How should we coordinate the work around the common interfaces, should
> we put up a new
> tiny project to handle it, where we all (Mark, Bill, Erik, Rickard)
> can commit changes?
> Or do you have any other suggestions?
Sorry Mark, I missed your mail about the github project. I'll use it
from scala-tools.org when it is up there.
/ Rickard
On 10/14/09, Rickard Nilsson <rick...@gmail.com> wrote:
> Quoting Rickard Nilsson <rick...@gmail.com>:
>
>> Hi,
>>
>> This is certainly a great idea. I'll implement it in ScalaCheck
>> 1.7-SNAPSHOT.
Great, thanks!
>> How should we coordinate the work around the common interfaces, should
>> we put up a new
>> tiny project to handle it, where we all (Mark, Bill, Erik, Rickard)
>> can commit changes?
>> Or do you have any other suggestions?
>
> Sorry Mark, I missed your mail about the github project. I'll use it
> from scala-tools.org when it is up there.
I have no problem if someone else wants to host it or wants to do it
differently. I just wanted to get it moving. I have a first draft
that I am ready to push, but there are two naming questions. What
should the package name be and what should the artifact name be? I'm
working with 'sbt' as a package name and
org.scala-tools-testing#test-interface as organization/artifact IDs.
Thanks,
Mark
Take a look and let me know what you'd like to see done differently.
Thanks!
-Mark
public Result run(String testClassName, TestFingerprint fingerprint, Param[] params);
On 10/16/09, Josh Cough <josh...@gmail.com> wrote:
> Hi guys. I'm having some problems with the API, but I think they are hard to
> see at first. One of the problems, I think, would be solved by changing the
> signature of the run method to:
>
> public Result run(String testClassName, TestFingerprint fingerprint,
> Param[] params);
>
>
> A user might want to communicate some restraints on which test they want to
> run. For example, they might want to only run tests in a particular group:
> Slow Tests. They could pass the groups in with the params. There might be a
> better way to do this, but at least this would make it possible, as it seems
> impossible (or quite difficult) given the current API.
testClassName is the name of the test class to run, not individual
properties/examples/whatever each test framework calls them. From my
point of view, sbt has already determined what are test classes or
modules and is asking the framework to run a specific test. It will
call 'run' for each test to run.
I think parameters could be useful in general though. Definitely
don't take this as a final API, just a draft.
> I think the problem is actually a lot deeper than that shallow example. A
> general way to tap into, or control discovery would be very helpful, but I
> need to think it through a little more. I'll try to write more tonight.
The API is meant to be a simple "run this test please" that leaves the
details of actually running the test to the framework. The client of
the framework is expected to handle providing the tests to run.
Implementing it should be similar to the ScalaTestRunner for sbt.
-Mark
On Fri, Oct 16, 2009 at 4:49 PM, Mark Harrah <dmha...@gmail.com> wrote:
>
> Hi Josh,
>
> On 10/16/09, Josh Cough <josh...@gmail.com> wrote:
>> Hi guys. I'm having some problems with the API, but I think they are hard to
>> see at first. One of the problems, I think, would be solved by changing the
>> signature of the run method to:
>>
>> public Result run(String testClassName, TestFingerprint fingerprint,
>> Param[] params);
>>
>>
>> A user might want to communicate some restraints on which test they want to
>> run. For example, they might want to only run tests in a particular group:
>> Slow Tests. They could pass the groups in with the params. There might be a
>> better way to do this, but at least this would make it possible, as it seems
>> impossible (or quite difficult) given the current API.
>
> testClassName is the name of the test class to run, not individual
> properties/examples/whatever each test framework calls them. From my
> point of view, sbt has already determined what are test classes or
> modules and is asking the framework to run a specific test. It will
> call 'run' for each test to run.
>
When you say "run a specific test," do you mean "run a specific test
class"? Sounds like you are conflating the two:
/* Specifies how to identify classes that are tests.*/
public TestFingerprint[] tests();
One thing I tried very hard to do in ScalaTest was be clear on
terminology. A "test" in ScalaTest is anything that 1. has a name, 2.
can be started, and 3. either succeed, fail, or be pending. A "suite"
is a collection of tests. I think vague and conflicting usage of terms
makes an API harder to learn and use.
What "test" means is very confused, for example, in the JUnit API. A
test method is a test in JUnit. A collection of tests in a class is a
TestCase in JUnit 3 at least. A TestSuite is a collection of
TestCases, and both of those implement the Test interface. And the
convention is to name TestCase classes with names ending in Test. So
"test" in JUnit kind of means everything and therefore nothing.
You need not adopt ScalaTest's terminology, but if not, I'd recommend
you at least always say "test class" whenever you talk about that
concept. Because the main thing a test is in any of these frameworks,
JUnit, TestNG, ScalaTest, specs (so long as you substitute "test"
every time you see "example") is that named thing that can start and
either succeed or fail.
The way ScalaTest's terminology works is a suite of tests can be any
collection of tests. A "test class" can be a suite of the tests inside
it, be they test methods or test functions or something else. A class
whose instances can hold onto other classes that represent suites of
tests is also a suite because it is a collection of all those tests. A
"Spec" is a suite of tests that has the BDD style of input and output.
So in your API if you want to be clear you are talking just about
classes, I would call them "suite classes" in ScalaTest terminology.
If you'd rather use the word test, then I'd suggest calling them "test
classes" not just "tests."
Thanks.
Bill
----
The parameters needed are extra options specific to the framework.
The test class to run is already identified and whether it is a class
or module. The runner needs to use the provided ClassLoader and
Logger. The run method will be called once for each test
class/module. It won't have all names passed at once. So, the extra
options might be similar to those passed to the main method, but the
interface can't be the same as calling the main method.
-Mark
Right, I agree that how sbt gets the arguments from the user is the
tool's problem.
> A final note about discovery - we still might want to make discovery a part
> of the interfaces, or even have an implemented version as part of this
> project. I imagine other tools could make use of it as everyone has to do
> discovery. But, that is separate to the everything above.
The TestFingerprint interface could be more general than subclass
detection. I don't know what that would look like, though. If it
were made more general, I would wonder if your NetLogo tests should be
run by a custom framework.
-Mark
I think String[] is fine for extra options, but it can't be the same
as just using the framework's main method. The runner needs to use
the provided ClassLoader and Logger, for example.
> Mark, how does this effect things like test-only? You'd normally have
> something like this right?
>
> sbt> test-only SomeClass AnotherClass YetAnotherClass
>
> Now you'll have to recognize that the things on the end might not be
> classes.
>
> sbt> test-only SomeClass AnotherClass YetAnotherClass -t things that aren't
> a class.
I don't think this would be a problem. Class names aren't unescaped
from things like $plus to +, so we can do something like separating
names from -- or some other syntax. I'll worry the details after
we've got an interface.
> Finally, since these interfaces can likely be used by other tools, maybe we
> should change the package name? How about org.scalatools.testing ?
Sure. Please feel free to modify the interface and post patches (or
pull requests or whatever).
-Mark
I've not been following the discussion in detail, but here's my 2c.
Instinct [1] a Java BDD framework I wrote a while back has a bunch of
ways to detect what to run. It doesn't actually use subclasses, but
naming conventions, annotations, etc. I've been meaning to write an
sbt integration point to it for a while, so whatever gets added I'd be
happy to provide an implementation of this interface for Instinct (it
already has exactly this).
Tom
[1] http://code.google.com/p/instinct/
--
tom adams | e:tomjadams<at>gmail.com
public interface Framework{public String name();
public boolean isSuite(Class c);
public Runner testRunner(ClassLoader testClassLoader, Logger logger);}
On 10/19/09, etorreborre <etorr...@gmail.com> wrote:
> I think that we may go through a too complicated road here, because
> frameworks may have very different way to run and report results. For
> example in specs you can nest examples and subexamples indefinitely
> and I don't know how to use the current interface with that.
>
> What would be simpler is:
>
> Framework.java:
>
> /** return a Runner using the ResultOutput to display
> - descriptions
> - test results
> - run statistics
> */
> public Runner testRunner(ClassLoader testClassLoader, Logger logger,
> ResultOutput output);
>
> ResultOutput.java
>
> /** write to the console */
> public void write(message: String)
>
> Runner.java
>
> /** return true if the tests are not passing for whatever reason */
> public boolean run(String testClassName, TestFingerprint fingerprint,
> String [] args);
>
> Do you see any issue with this approach?
The Logger is supposed to be used for the purpose of the ResultOutput.
If you would prefer ResultOutput, that is fine with me. The run
method above is basically all sbt needs. It just needs to know on a
test suite level whether the suite passed or failed so that it can
implement test-quick and test-failed. However, it would be useful as
a user to have the number of tests passed/failing/whatever and a
summary of failures be uniformly reported. I think that the rest of
the logging/output can be framework specific. So, I like returning a
TestResult[] as Josh suggests.
As Eric indicates, the problem with the event listener is that each
framework will have a different event hierarchy and events complicate
the interface. There could be a basic TestEvent interface and each
framework could implement its own hierarchy, but it should be
information that a client is not required to handle. That is, run
should still return TestResult[].
> On Oct 19, 3:03 pm, Josh Cough <joshco...@gmail.com> wrote:
>> I found yet another issue with Runner. It would be nice if tools had
>> immediate info of when test is starting, is finished, and what its result
>> is, as well as an entire suites. I suppose this issue could be resolved
>> with
>> the Logger, but thats probably not the best way.
I don't see a problem with this. I think it is the user that needs
the immediate feedback, not the tool. The framework can log to the
Logger as it runs and inform the tool of results after the suite
completes, .
-Mark