Problem
-
http://drupal.org/project/issues/search/drupal?issue_tags=Testing+system
#1563620: All unit tests blow up with a fatal error
#1565718: Script test runner does not clean after fatal error
#1188316: DrupalUnitTestCase incompatible with any classes with destructors that access the database
#1541958: Split setUp() into specific sub-methods
#1376122: Stream wrappers of parent site are leaking into all tests
#1215104: Use the non-interactive installer in WebTestBase::setUp()
...
Goal
- Pave the way for replacing Simpletest with PHPUnit.
Battle plan
- There's no way we're going to convert 40,000+ assertions over night. We aim for concurrent/parallel testing framework support in D8.
- drupal.org testing infrastructure won't support PHPUnit over night. The testing infra team works on a new job manager anyway already, so patching PIFR makes no sense.
- The testing framework is technically detached from Drupal core. It was beneficial to add it to core for D7 to foster adoption, but otherwise it shouldn't have been added. The new web tests should be designed in a cross-major-version compatible way.
- This effort requires involvement and hard work from all testing system experts, but everyone is extremely busy with getting D8 ready and soon out of the door. People will shoot us and get very angry if testing system changes will suddenly break their last-minute work. We will not do that. An effort like this should start at the beginning of a release cycle.
- Nevertheless, we cannot leave Simpletest in its current state, since it is broken in many aspects and continuously hinders core developers. We have to improve it in parallel.
- In concrete terms:
- Long-term (D9)
-
- PHPUnit for unit tests and + Mink + Guzzle + Goutte for web/integration tests. Quite potentially Behat for BDD tests.
- No more remnants of Simpletest in core and contrib.
- Short-term (D8)
-
- Improve Simpletest where possible and attempt to bring it more in line with PHPUnit to make the long-term transition easier.
- Try to allow developers to write PHPUnit tests (not in core) by preparing the necessary (code) infrastructure if possible, without officially supporting it. (i.e., base classes for running unit/web tests with PHPUnit.)
- Start to hammer on this after feature freeze until release.
Agreements
- 1 test site (no parent site leaking into child site).
- PHPUnit is used by everyone in the PHP world.
- Remove dependency on full site + Simpletest module being installed.
- Write results/log into JUnit .xml results file.
- Install Drupal with (stripped down) testing profile + class-specific module(s).
- TBD: Kick off test runs and show results in a separate web app ? - No Simpletest in core.
- TBD: No testing framework in core. [barrier for novice contributors?]
- Guzzle as internal browser, because we should have it in core anyway.
- PHPUnit has assertSame() for type-strict comparisons (== current assertIdentical()).
Details
- Remove dependency on installed parent site with Simpletest module.
- Discourage/remove custom assertion messages.
- assertIdentical by default (strict type comparison)
- setupBeforeClass() (and create fixtures/install Drupal) only once per test case
- Unit tests
-
- #1801176: Deploy a PHPUnit system with a bottom-up approach
- #1872006: Add parity test classes for lib/Core and lib/Component
- #1901670: Start using PHPUnit for unit tests
- Dependency Injection and Dependency Lookup
- Overriding and Overwriting
- More information
- Web tests
-
- Use Guzzle + Goutte (Mink) instead of custom internal browser
- Install testing profile without Node module dependency
- Default configuration for modules involved in a test
and: Test helper methods for all involved modules in a teste.g.,
$this->drupalCreateUser()»$this->getHelper('user')->createUser()/->createRole()/ ... - Use the non-interactive installer, remove WebTestBase's special installation procedure.
- $modules - just call module_enable($modules);
- Behat tests
-
- Dedicated issue: #2232271: [Meta] Use Behat for validation testing
- Leverage and re-use infrastructure of default testing configuration + test helpers for Behat natural language parsing, Feature contexts, steps.
- Figure out the generic natural language that works for 10,000+ modules. Start with Drupal Commons tests. The steps are in Ruby but easy to convert.
- Dependency management
-
- Have all required libraries ship with core. Testing must not involve barriers.
Moshe: Though nice, I don't think this is feasible. PHPUnit has versions, updates, installs via PEAR, etc. we can't take all that on.
sun: The version is actually a reason for including it, so as to make sure that all tests are compatible. PHPUnit has BC breaks in new versions, too, like any other software.
- Have all required libraries ship with core. Testing must not involve barriers.
- Test Bot
-
- qa.drupal.org testbots need to be able to run phpunit and interpret its results (Junit XML).
- Related: #1553256: [meta] Replace testbot clients in testing infrastructure with travis-ci
- Related: #1563758: Testbot TNG - Various Automated Testing Tab UI Mockups
- Dissent / Unclear
-
- PHPUnit vs. atoum -- pretty much every other PHP app/component uses phpunit. That debate appears to be needless bikeshed.
- PHPUnit has excellent documentation.
- No need to re-invent the wheel for PHPUnit usage docs - there's lots of user documentation everywhere:
- The web generally has tons of useful PHPUnit resources:
- Wordpress' migration: http://core.trac.wordpress.org/ticket/17749
- Process isolation: http://kpayne.me/2012/07/02/phpunit-process-isolation-and-constant-alrea...
- PHPUnit without PEAR: http://melikedev.com/2012/01/25/php-phpunit-use-phpunit-without-pear/
- To quote @sun on twitter:
#Wordpress, #Joomla, #ezPublish, #typo3, #phpBB, #Silverstripe, #CakePHP, #Symfony, #Doctrine, #zf2, ... are all using #PHPUnit.
- Whether to ship phpunit.phar with core. (don't add new barriers)
- PHPUnit vs. atoum -- pretty much every other PHP app/component uses phpunit. That debate appears to be needless bikeshed.
Resources
PHPUnit + bridge efforts:
https://www.acquia.com/upal
http://denver2012.drupal.org/content/upal-proposed-test-framework-drupal-8
https://github.com/weitzman/upal (has a unnecessary dependency on Drush)
Behat:
#1551600: DBehave!
http://docs.behat.org/guides/1.gherkin.html#backgrounds
http://drupalcode.org/project/doobie.git/blob/725cc24ff3d4acca36d68f9f19...
http://drupal.org/node/1578324
Comments
Comment #0.0
sunUpdated issue summary.
Comment #0.1
sunUpdated issue summary.
Comment #0.2
sunUpdated issue summary.
Comment #0.3
sunUpdated issue summary.
Comment #1
gagarine commentedatoum
I just get a small presentation of it. 30s after I was searching if someone was thinking to move away of us hacked Simpletest.
It's nice, easy, fast, modern and flexible.
Comment #2
mageekguy commentedI'm the creator and lead developer of atoum and i have no problem to help you to use it instead of SimpleTest.
Comment #3
sun@mageekguy: Thanks a lot for taking the time to register and letting us know! That means a lot. :)
README.txt
In general, this entire effort will still take some more time to actually take off. It will take a shitload of careful planning and architectural design work to make the transition possible, without losing or endangering the existing test coverage of Drupal core (with ~37,000+ assertions) as well as the existing test coverage of ~2,000+ contributed modules (total amount of assertions unknown).
In fact, this very issue totally is a placeholder at this point only. I created it after wasting entire days of developer time with duct-taping our current testing framework, and so the issue summary is totally not in a format that was intended for public consumption ;)
That said, regardless of which new testing framework we're going to choose, I actually see a very high chance for having to support multiple testing frameworks at the same time — i.e., kinda circling back into the above; we're not able to just simply throw away tens of thousands of lines of code of existing test coverage, and due to that massive amount, as well as a constantly/daily changing Drupal core HEAD target/tip, a end-day/deadline for migrating all tests also seems impossible. The only exception to that might be a "compatibility layer" between the new testing framework and our current (which basically is the idea of Upal; which attempts to bridge and port our current base test classes to PHPUnit).
Another reason for possibly supporting multiple frameworks could be that we're currently migrating Drupal core's base system to Symfony, and Symfony components ship with their tests bundled for each component starting from 2.1 (dunno whether Symfony changed that because of my complaints, but either way, totally appreciated ;)), and their tests are based on PHPUnit currently.
Speaking of base test classes above, Drupal implements two entirely different types of tests: straight unit tests and functional/integration tests. The former (unit) tests are fairly easy to migrate to "whatever", since they do not have or use any special methods that wouldn't exist in any other testing framework. But alas, we only have a very small amount of unit tests in the first place, since up until Drupal 8.x/HEAD, core didn't implement any DI container and pretty much no OO code in general, but most functions in Drupal require some other subsystems to be up and running, so it wasn't possible to mock anything for unit tests at all.
Thus, the majority of existing tests is based on our WebTestBase, which actually installs a complete Drupal site like the regular Drupal installer for every test being executed, using a random database prefix and some logic baked into Drupal's (regular runtime) core that re-routes all HTTP requests originating from WebTestBase into the "child site under test" (the db-prefixed one). Based on that, every test is able to specify additional modules to install into that child site, in order to test various combinations of modules and configuration and content/data and user input and whatnot.
It is fairly important to understand that Drupal, unlike PHP frameworks, is a modular, extensible, and entirely "configuration-based" application layer, whereas the configuration can be and is supposed to be changed via the UI. This inherently means that, for the most part, it makes more sense to test module functionality in an actual Drupal environment instead of attempting to test it in a mocked unit testing environment, since the results can easily vary. This doesn't mean there's no point in unit tests (there totally is and we totally should have more), but in most cases, the results are vastly different based on the order in which modules and thus their hooks/events are executed. Thus, right now, most of Drupal's tests are trying to verify the expected functionality from an end-user perspective, which apparently matters most for our end goal of delivering a product that works and can be configured and enhanced from the UI/frontend.
So for the most part, I doubt that those web/functional/integration tests are going to change dramatically, since neither PHPUnit nor atoum seem to provide any solution for what we're doing there — both of them seem to focus on unit tests only. In turn, this means we'll have to port that WebTestBase layer onto whichever testing framework anyway. We're currently trying to at least align those tests with PHPUnit's stance of setting up a testing environment as well as fixtures in #1411074: Add a flag to set up test environment only once per test class; introduce setUpBeforeClass() and tearDownAfterClass() [PHPUnit] (which probably isn't unique to PHPUnit only).
Due to massive adoption of PHPUnit in other PHP projects and also common support in IDEs, there has been a some push towards PHPUnit recently. Although I've to admit (and heard similar feedback from fellow Drupalers) that atoum looked very attractive at first sight ;) (although I should note I didn't really dive in very deeply, merely glanced over the front page/readme on github) OTOH, PHPUnit's very extensive documentation and tutorials on authoring and designing tests is a very compelling counter-argument, which definitely helps a community like Drupal, since we need to teach thousands of contributors and users with (highly) varying levels of expertise in how to write tests. Also, when I first looked into PHPUnit, it looked "old" on the surface, but their latest development branch and "plugin" code is actually modern (or modernizing) inside.
Given that, overall, I'm not sure why atoum was created as a separate framework, instead of improving PHPUnit? ;) (yes, lemme play the provocative card here :P, but alas, that's a serious question which I'm absolutely sure of coming up, repetitively even)
Lastly, speaking of "Given", there's a great desire to leverage BDD/Behat style testing in Drupal tests, since probably ~30% of our existing web/functional/integration tests could be semi-easily rewritten into BDD/Behat's macro testing language — which means a huge potential for us, since writing such tests does not require any PHP knowledge, so it can be done by total newcomers/novices, which in turn is the opportunity (believe it or not) for getting completely new contributors involved, who may or may not turn out to be the next Drupal core maintainer 5 years later; i.e., affecting the very heart of the Drupal community.
HTH to give some high-level perspective. 1st paragraph still takes effect, but of course, any upstream testing framework info upfront helps to shape a better picture. :)
Thanks!
Comment #3.0
sunUpdated issue summary.
Comment #4
bennetteson commentedAtoum is more attractive and more easy to use.
Comment #5
gagarine commentedFor a "web client" to do functional test http://mink.behat.org/index.html
mink is integrated out of the box with PHPUnit, Behat and Symfony2 but any integration is certainly easy http://mink.behat.org/phpunit.html
And for functional test in natural language, take a look at behat (it's used mainly for https://en.wikipedia.org/wiki/Behavior_Driven_Development ...).
EDIT: didn't see the issue summary evolve from the last time I read it.
Comment #5.0
gagarine commentedUpdated issue summary.
Comment #6
Sylvain Lecoy commentedIf you find this paper good Agile Unit Testing you can add it as a resource guidelines regarding unit testing.
Comment #6.0
Sylvain Lecoy commentedUpdated issue summary.
Comment #6.1
sunAdded discussion notes and battle plan.
Comment #7
sunI've copied my notes from various discussions with various people into the issue summary, and revamped it entirely, including the envisioned battle plan.
Shapes the rough edges. I'm aware that it doesn't contain actual + actionable steps for getting a new testing system (code) infrastructure in place (i.e., base classes and so on). There's a tonne of things to figure out there. But frankly, I don't think anyone has time to discuss that until Dec 1st, so I'd prefer to defer that discussion until then, but of course wouldn't mind if anyone would jump on the gun and try out some initial PoC code, especially regarding Mink-based web tests.
Nevertheless, moving into core queue.
Comment #7.0
sunClarified and completed battle plan.
Comment #7.1
sunMore clarifications, moved PHPUnit docs links.
Comment #7.2
sunQuote.
Comment #8
Sylvain Lecoy commentedAdded a POC of a block unit test re-factored to use PHPUnit #1801176: Deploy a PHPUnit system with a bottom-up approach.
Comment #9
fgmFWIW, there are already actual sites using PHPUnit tests in a Drupal setup: some customers of mine wouldn't bend over their testing and CI practice and chose to develop unit tests for their custom code using PHPunit only, no Simpletest runner.
Comment #9.0
fgmAdded Unit test.
Comment #9.1
Sylvain Lecoy commentedAdded Issue #1801176 in the Unit test section.
Comment #9.2
Sylvain Lecoy commentedtypo
Comment #10
fgmMore about this:
Comment #11
franskuipers commentedHow can we take this initiative further?
I was very happy to see PHPunit sneaking into core with #1901670: Start using PHPUnit for unit tests! And because I want the learn and get experience with PHPunit I started to work on this in #1938184: Convert Drupal\Core\Utility\Color\ColorTest to PHPUnit and #1938068: Convert UnitTestBase to PHPUnit.
Looking around more into all PHPunit related issues I realised it is not a concerted effort yet.
Some ideas to bring this further:
I would like to help/carry on with this issue, but need some guidance as how to proceed.
Comment #12
robloachThe PHPUnit Blocker tag is moving a few parts of Core over to PHPUnit.
Comment #12.0
robloachAdded Issue #1872006 in the Unit test section.
Comment #13
larowlanThis is 9.x territory now, alas
Comment #14
larowlanSo I've started plugging on a bridge class LegacyWebTestBase that extends UnitTestCase (PHPUnit) and has 1:1 methods with SimpleTest WebTestBase
I've pushed this to a branch in my core sandbox
I have it to the point where you actually see the class make Curl requests (I have some scaffolding in for Mink/Goutte but leaving it with Curl/existing logic until stuff is at least running).
Commit summary (from sandbox)
To see where I'm at
It will error out because no $_SERVER['TESTING_BASE_URL'] provided.
Edit your settings.php and add
$_SERVER['TESTING_BASE_URL'] = 'http://d8.local';using your local url.Sample output
Note This will hose your existing site, we still have leakage between the containers/compiled twig
Comment #15
moshe weitzman commentedI still really think we should ditch simpletest and rely solely on phpunit. We have tried to plug these holes for *years* and been unsuccessful. The mental burden will be so much lower if we only have one Drupal, and rely on phpunit to be our test runner. I will personally write the (small) patches to help test bot run phpunit instead of simpletest.
Thanks for working on this.
Comment #16
catchThe test bot is already running PHPUnit and there's issues to convert existing core unit tests to use those. No bridge, just one-by-one rewriting the unit tests.
What we don't have is issues to convert functional tests away from PHPUnit - we're still going to have some functional tests, and PHPUnit isn't really designed for those. For that I think it'd make sense to start using Behat against core - which would get us functional JavaScript testing as well.
Comment #17
larowlan@catch I wasn't trying to bridge unit test, but functional tests aka WebTestBase.
The idea being get something going with PhpUnit as the runner and then integrate Mink as the browser instead of SimpleTest.
Comment #18
jrockowitz commentedI am just starting to learn D8 and Symfony and was looking into how both handle functional testing. I found functional testing in Symfony very intuitive (http://symfony.com/doc/current/book/testing.html#functional-tests).
I started reading this issue and could not help but wonder why we wouldn't consider extending Symfony's WebTestCase and use it to replace SimpleTest. My guess is it might require Drupal 9 to include more components from Symfony, which seems to be the direction things are going for D9.
I am sure I am missing something ... but sometimes it is worth asking some simple questions when trying to solve big problems.
Comment #19
moshe weitzman commented@jrockowitz - thats a great find! Symfony's webtestcase simulates an http client, but there is no actual http involved. thats a nice speedup. See http://symfony.com/doc/current/book/testing.html#working-with-the-test-c...
I'd be fine with Symfony's WebTestCase or Behat for our functional tests. Behat uses http which is unfortunate but writing tests is approachable to anyone.
Comment #20
fgmActually, you don't have to use HTTP at all to run behat, especially when using the Drupal extension: tests can run either using the API, using Drush, OR using and actual HTTP client (Blackbox API). It's simply a matter of tagging your scenarios so that the extension knows how to run them, and configuring the drivers in the test config.
http://www.dspeak.com/drupalextension/drivers.html
Comment #21
larowlanI wonder if making this 1:1 compatible phpunit+mink replacement for simpletest means this could be in 8.1.0 in a semantic-version world?
Comment #22
owen barton commentedIf I am reading it correctly, http://extensions.behat.org/symfony2/ provides a Behat driver that runs requests against the Symfony kernel directly - this would seem to give us the best of both worlds - write functional tests in Behat, but avoid the HTTP overhead.
Comment #23
Crell commentedJust a note, I'm not sure that Drupal's bootstrap is at the point yet that it could handle a non-true-HTTP functional test. A lot of progress has been made in that direction but especially things like the installer may not be able to handle it. I know Mark ran into lots of issues between simpletest and the installer when trying to separate out the bootstrap into better kernel layers.
That said, if we could pull off simulated-request-based testing that would a HUGE win, and I fully support it. Having taken that approach on a Silex project recently I much preferred it to what we do now in Simpletest.
Comment #23.0
Crell commentedAdded issue 1901670.
Comment #24
chx commentedsimpletest is not broken beyond any repair. As I have mentioned in several issues: as long as you need to install a child Drupal to test and run it with Drupal you will have problems. That is irregardless whether we use our own browser or someone else's.
Comment #25
chx commentedI am told Ditch is not a PHP project being considered. What do I know.
Comment #26
catchPHPUnit is already in.
If we're going to make any testing changes apart from individual conversions of some functional/integration tests to PHPUnit, I'd want to focus on js testing. JS testing will also individually convert some simpletests that are working around not being able to execute js, then there's a discussion to be had about what happens to the tests that don't belong to either browser testing or PHPUnit.
The issue for that is #237566: Automated JavaScript unit testing framework , so postponing this one.
Comment #27
jessebeach commentedComment #28
sunComment #29
larowlanSpoke to omissis in irc who's been experimenting with this.
Encouraged him to create a new issue to track his approach - he created #2283257: [meta] Porting Drupal Integration and Functional TestCases to PHPUnit
Have added it as a child.
Comment #30
larowlanBrowserTestBase is in
Comment #31
catchEverything here except actually removing simpletest can be done in a minor version.
Comment #33
larowlanI think this is now closed - fixed
Now that #2469721: Add functionality to store browser output to BrowserTestBase is in, BTB and JTB have feature parity.
Time to open a meta to start the conversions?
Comment #34
catchHave we marked everything in Simpletest @deprecated at this point?
Comment #35
larowlanNo. We haven't deprecated WebTestBase yet. Maybe that is the next step?
Comment #36
webchickI think before doing that, we need to ensure all the documentation for writing a test is updated to reflect the New World Order™ because by deprecating WebTestBase, we'd be in effect requiring all future web tests to be written this way.
Comment #37
berdirAlso, we should probably convert a bunch of existing tests to see if that (feature parity) is actually true. We thought that for the new KernelTestBase too and fond a whole bunch of issues and missing features will actually porting the tests.
Comment #38
catchThat sounds right. Once we're getting there with the conversions, I think we could add the deprecation notice.
Comment #39
jibranAnd then there is #2735005: Convert all Simpletest web tests to BrowserTestBase (or UnitTestBase/KernelTestBase).
Comment #40
klausiI opened #2750461: Remove Simpletest UI because we don't want to maintain a graphical test runner which is almost a duplicate.
This issue was postponed in 2013 to get a javascript testing framework, this is now done with the introduction of JavascriptTestBase using PhantomJS.
Since this issue is old and contains all kinds of details that we already solved which are not relevant anymore I suggest to call this fixed in the sense that this successfully paved the way. Thank you all!