Problem/Motivation

We have no functional tests, so we can't enforce expectations about things like which commands should be present and how they should behave.

This is necessary during refactoring, to be sure we aren't regressing.

Proposed resolution

Create a test base class which can create or mock an app for us.

For some tests, use Symfony\Component\Console\Tester\CommandTester to run commands and capture output.

For some tests, require dependencies on mock 'hard' resources such as loading a fixture image.

Remaining tasks

User interface changes

API changes

Data model changes

Comments

Mile23 created an issue. See original summary.

mile23’s picture

Status: Active » Postponed

This issue is immediately postponed on #2638466: Add a php container to make the codebase easier to test., so we can build our test infrastructure on the new service container.

mile23’s picture

StatusFileSize
new3.3 KB

...Tho of course there's already a patch. :-)

It depends on the service providers being defined in #2638466: Add a php container to make the codebase easier to test. so it might need a reroll or scrap and restart later.

mile23’s picture

Status: Postponed » Needs review

The container is in, let's rock.

  • Mile23 committed d05d4f2 on 2676854-write-functional-tests
    Issue #2676854 by Mile23: Write functional tests to prevent regressions
    
mile23’s picture

This is the patch in #3, plus a little shuffling to put ConsoleCommandProvider in the proper place.

If you run it you'll see that we lost the travis command in there somewhere. It probably doesn't have a command service.

So this issue is about using the CommandTester class to run commands and checking expectations about their output. You can see an example of this in StatusCommandTest, which was an easy test to write because the status command doesn't do much. :-)

CommandTester just captures the output of the command run and then you can examine the text that came back. You can also examine the state of the command itself because you still have an instance of it.

Testing gets more complicated with, eg, the run command which has a lot of dependencies.

jthorson’s picture

Here's where I wanted to sneak some of the changes in before testing.

If CommandTester could capture the JobResults object (part of #2655718: Create the BuildResults), we would then have a per-build step status reported back from each individual step executed within something as complicated as the RunCommand ... and given various configurations, we could iterate over these results to confirm the expected behaviour. While admittedly, this doesn't give us coverage of the JobResults calculation itself, it would give us a significantly larger chunk of coverage than what we have today ... and with much lighter test logic!

  • jthorson committed 4bf4362 on 2676854-write-functional-tests
    Issue #2676854 by jthorson: Removed obsolete Travis command from...
mile23’s picture

Functional tests.

Of command output given input.

That's what this issue is. :-)

If CommandTester could capture the JobResults object

Let's now say that the JobResults object is a service parameter set by the command.

This means that for testing you'd mock a service, like docker or whatever, put it in the container, create a command, and inject the service. Then look at the job.results service parameter when it's done.

Assert your expectations, and bob's your uncle.

But not in this issue. :-)

jthorson’s picture

Status: Needs review » Reviewed & tested by the community

Let's rock!

mile23’s picture

Assigned: Unassigned » mile23
Status: Reviewed & tested by the community » Needs work

There is only one functional test here.

jthorson’s picture

So this issue is about using the CommandTester class to run commands and checking expectations about their output.

I took this to mean that this issue is about getting the framework in place, not completing the full list of functional tests (which could take weeks, depending on how far we want to take it).

Committing this allows us to incrementally add functional tests - as opposed to building up a large suite of them, but not adding any until we've built them all ... It would make sense to me to put in what we've got here, and isolate debates over the actual implementation of various functional tests in their own issues.

jthorson’s picture

Status: Needs work » Needs review
StatusFileSize
new2.2 KB

So ... something like this?

- drupalci/scratch is a new empty container (Copy of the official 'scratch' image; but we can't use that directly as 'scratch' is a reserved word since Docker 1.8.1.
- This doesn't actually provide coverage of execution of the 'docker pull' command itself, but I'm assuming that if we have a valid ImageManager, and attempt to 'pull' after verifying the proper output text, we will either get a pull, or an API exception back from Docker. I don't see a way of explicitly validating the pull succeeded, as the progress bar output doesn't show up in the CommandTester->getDisplay() output; but I assume that the testing framework will capture any errors which creep up there.

jthorson’s picture

StatusFileSize
new1.84 KB

Ooops ... IDE "helping" is hurting. Clean patch here. :)

  • Mile23 committed 7687f20 on 2676854-write-functional-tests
    Issue #2676854 by jthorson, Mile23: Write functional tests to prevent...
mile23’s picture

These tests only have to show that when we change the output system, we still have the same output. We could make it super-perfect, or not that perfect at all. The above commit isn't all that perfect. :-)

And: A little bit like that, yes. But instead of requiring that we hit docker, we can mock the docker service with predictable results for the pull command. My test in the commit is bad and just uses a bad image name, so there's a @todo about that.

Also moved registering DockerServiceProvider to inside DrupalCIServiceProvider so it's always there.

mile23’s picture

Assigned: mile23 » Unassigned

Remaining:

  • Mock the docker service as per #16 for tests which need docker services.
  • Make at least minimal tests for all commands.
mile23’s picture

Status: Needs review » Needs work
Mixologic’s picture

For the particular example jthorson posted above, we're wanting a functional test that proves that swapping out the docker library doesn't break anything else, so we do want a docker mock for other tests, but we want an end to end that includes the real library.

We probably want child issues and call this a meta, so that we dont get confused about different aims (being able to prove that the output changes are okay, vs being able to prove that the docker changes are okay).

mile23’s picture

OK so then we also need a TESTING.md to explain that you need to be running in the VM or whatever, with all the dependencies.

Mixologic’s picture

Having a doc explaining the nuance does sound like a good idea. We want functional regression tests, and many of those will probably need to be running in the vagrant VM. and we want unit tests, which shouldn't have any sort of dependency like that. Im currently working on a 'testing goals/policy' doc, detailing where we'd like to end up and how we'd like to get there.

mile23’s picture

Title: Write functional tests to prevent regressions » [meta] Write functional tests to prevent regressions
Category: Task » Plan
Issue summary: View changes
Status: Needs work » Active

OK, it's a plan. :-)

mile23’s picture

mile23’s picture

Moved branch 2676854-write-functional-tests to 2679673-write-output-tests

Mixologic’s picture

Component: DrupalCI console script » Testrunner Tests
mile23’s picture