Right now, the tests are very useful, but only test overall command files output and behavior. It cannot be used to test individual functions, as I discovered in #1132902: performance issues with huge tables.

It would therefore be useful to allow both types of tests. In the above issue, I have rolled my own bootstrap code, but that should probably be pulled upwards in a common class.

Comments

anarcat’s picture

Status: Active » Needs review
FileSize
13.67 KB

Here's a first pass at it. The unit tests fail here after the patch, but I believe they failed before too, mostly because i don't have a mysql user sitting around to create drupals, but also some weird local implementation bugs. I also believe it's testing my system install of drush 4.4 instead of the local 5.x one. :)

moshe weitzman’s picture

Status: Needs review » Needs work

I'm of mixed opinion about loading drush code in the same process as phpunit. I'm a little skeptical that processIsolation will work well but it is worth a shot. Please test this in particular. Also, the test suite is passing for me and Jenkins. Be sure to customize phpunit.xml.dist as needed.

anarcat’s picture

Are you saying I need a unit test showing you process isolation for unit tests works? :P I'll at least try out the process isolation...

greg.1.anderson’s picture

It is my opinion that in general, functional test should only test methods and functions that (a) return a result and (b) operate only on their own object fields and function parameters, using no external state and producing no side effects. Exceptions can be made for files, provided that said files are specified via a function parameter or object field that can be initialized to point to test files in the functional tests.

Under these constrains, process isolation is not necessary; however, any drush method that called drush_get_context, drush_set_context, drush_get_option, drush_get_command, etc. could only be tested in the application unit tests, and could not be called from the functional unit tests. There are a lot of drush methods that fall into this later category (e.g. nearly all command hooks), so perhaps it is only mildly beneficial to create functional unit tests following these guidelines. However, many drush routines currently exhibiting side effects could be refactored into a wrapper function with the same signature, that calls through to a refactored side-effect-less function that could be called from the functional tests.

Doing this would also improve the code over time, as a larger body of come became testable w/out side effects. I don't see a lot of value to functional tests + process isolation, because in my mind, one of the key benefits of functional tests is to verify that the body of code being tested is free of side effects. Without that, we might as well just stick with application-level unit tests, which already takes care of process isolation.

anarcat’s picture

I like your thinking there greg.

I think there is space for both approaches: test Drush commands and test drush functions. Command-level testing is useful because it allows for broader tests to be developed much more quickly than regular function-based unit tests, which need significant coverage to be effective for proper testing.

Can we just merge in the patch, which supports both approaches? Moshe?

anarcat’s picture

Status: Needs work » Needs review

I'd like to push this in now - it's getting hard to maintain those patches separately as unit tests continue to be developped.

moshe weitzman’s picture

Please do not commit this until I RTBC it. I'm not sure I want function level testing. Our current technique is pretty self explanatory. We are testing quite internal systems with it. See backendTest or contextTest. I don't really like to have to explain to folks which of our two techniques to use. I already get approximately 0% help authoring tests. I don't think this will help.

anarcat’s picture

I understand. I will not push this without your go. :)

One thing I hope to use this for is to provide an easy way to provide function-level unit tests within provision and other drush extensions.

I don't disagree with the current approach at all, and i also feel it's a great way to easily have people jump in and write tests. But I don't think we should keep people from writing function-level tests, which are also very useful.

moshe weitzman’s picture

Status: Needs review » Postponed

No compelling need yet. I'm interested if someone implements this and in the process lets us actually use phpunit's code coverage. code coverage doesn't currently work since all drush commands run in subprocesses.

anarcat’s picture

anarcat’s picture

Status: Postponed » Needs review

I've reworked this patch on the dev-real-unit branch. It's now working and we have a performance improvement for the test I ported:

anarcat@angela:tests$ phpunit --repeat 10 commandUnitTest.php
PHPUnit 3.4.14 by Sebastian Bergmann.

..........

Time: 2 seconds, Memory: 11.25Mb

OK (10 tests, 90 assertions)
anarcat@angela:tests$ phpunit --repeat 10 commandTest.php
PHPUnit 3.4.14 by Sebastian Bergmann.


Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.
Executing: /usr/bin/drush php-eval '$commands = drush_get_commands();print json_encode($commands['\''dl'\''])' --nocolor
.

Time: 6 seconds, Memory: 5.00Mb

OK (10 tests, 100 assertions)

3x performance improvement.

I am in the process of refactoring the bootstrap code to avoid duplication between the bootstrap process in the unit tests and the regular drush process.

moshe weitzman’s picture

Status: Needs review » Fixed

Fixed a few bugs and committed this. Lots of code moved around but thats about it.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

anarcat’s picture

Status: Closed (fixed) » Needs work

er. i can't seem to find any of the code from the dev-real-unit in drush 5.x, nor was I able to find a relevant commit at the said time. it seems that this was simply completely dropped, was it forgotten or refused?

i am trying to implement a test to show that drush_save_data_to_temp_file() fails to create two tmp files during a script (#1603744: can't create two temporary files), and this gets a bit silly as I need to do a lot of the test logic in an eval. With the patches that I sent here, this would have been trivial... while making tests faster.

moshe weitzman’s picture

Status: Needs work » Closed (fixed)
anarcat’s picture

Crap, sorry I missed this - don't know how. Maybe it's because I was looking only at the 4.x branch. :(