Showing posts with label tdd. Show all posts
Showing posts with label tdd. Show all posts

Thursday, June 18, 2015

Property-based testing primer

I'm a great advocate of automated testing and of finding out your code does not work on your machine, 30 seconds after having written it, instead of in production after it has caused a monetary loss and some repair work to be performed. This is true for many different kind of testing, from the unit level (which has also benefits for internal quality and design feedback) to the acceptance level (which ensures the stakeholders get what they need and documents it for the future). Your System Under Test can be a single class, a project or even a collaboration of [micro]services accessed through HTTP from another process or machine.

However, classic test suites written with xUnit and BDD styles have some scaling problems they hit when you want to exercise more than some happy paths: 
  • it is difficult to cover many different inputs by hand-writing test cases, so we stick with at most a dozen of cases for a particular method.
  • There are maintenance costs for every new input we want to test: each need some assertions to be written and be updated in the future if the System Under Test changes its API.
  • We tend not to test external dependencies such as the language or libraries, since we trust them to do a good job even if their failure is our responsibility. We chose them and we are deploying our project, not the original authors which provided the code "as is", without warranty.
Note that here I define input as the existing state of a system, plus the new input provided by a test (the Given and When part of a scenario) and output as not only the actual response produced by the System Under Test but also the new state it has assumed.

sort()


Let's take as an example a sort() function, which no one implements today except in job interviews and exercises.
Assuming an array (or list, depending on your language), we can produce several inputs for the function like we would do in a kata:
  • [1, 2, 3]
  • [3, 1]
  • [3, 6, 5, 1, 4]
and so on. When do we stop? Maybe we also need some tricky input:
  • []
  • [1]
  • [1, 1]
  • [2, 3, 5, 6, 8, 9, 1, 3, 6, 7, 8, 9]
Once we have all the inputs gathered, we need to define what we expect for each of them:
  • [1, 2, 3] => [1, 2, 3]
  • [3, 1] => [1, 3[
  • [3, 6, 5, 1, 4] => [1, 3, 4, 5, 6]
  • [] => []
  • [1] => [1]
  • [1, 1] => [1, 1]
  • [2, 3, 5, 6, 8, 9, 1, 3, 6, 7, 8, 9]  => [1, 2, 3, 3, 5, 6, 6, 7, 8, 8, 9, 9]
You can do this incrementally, growing the code one new test case at a time, but you have to do it anyway. Considering this can become boring and error-prone in this toy example makes you wonder what to do when instead of sort() you have a RangeOfMoney class which is key to your business and manages point-like and arbitrary intervals of monetary amounts (true story).

Property-based testing in a nutshell

Property-based testing in an approach to testing coming from the functional programming world. To solve the aforementioned problems (and get new, more interesting ones), it follows these steps:
  1. generate a random sample of possible inputs.
  2. Exercise the SUT with each of them.
  3. Verify properties which should be true on every output instead of making precise comparisons.
  4. (Optionally) if the properties verification failed, possibly shrink to find a minimal input that still causes a failure.

How does this work for the sort() function?

We can use rand() to generate an input array:
This array is composed by natural numbers (Gen\nat) and it is long up to 100 elements (Gen\pos(100)), since very long arrays could make our tests slow.

Then, for each of these inputs, we exercise sort() and verify a simple property on the output, which is the order of the elements:
This is not the only property that sort() maintains, but it's the first I would specify. There are possible others:
  • every element in the input is also in the output
  • every element in the output is also in the input
  • the length of the input and output arrays are the same.
Here is the complete example written using Eris, our extension for PHPUnit that automates the generation of many kinds of random data and their verification.

How to find properties?

How do we apply property-based testing to code we actually write every day? It certainly fits more in some areas of the code than in others, such as Domain Model classes.

Some rules of thumb for defining properties are:
  • look for inverse functions (e.g. addition and substraction, or doubling an image in size and shrinking it to 50%). You can use the inverse on the output and verify equality with the input.
  • Relate input and output on some property that is true or false on both (e.g. in the sort() example than an element that is in one of the two arrays is also in the other)
  • Define post conditions and invariants that always hold in a particular situation (e.g. in the sort() example that the output is sorted, but in general you can restrict the possible output values of a function very much saying it is an array, it contain only integers, its length is equal to the input's length.)

[2, 3, 5, 6, 8, 9, 1, 3, 6, 7, 8, 9] makes my test fail

Defining valid range of inputs with generators and the properties to be satisfied is a rich description of the behavior of the System Under Test. Therefore, when a sort() implementation fails we can work on the input in order to shrink it: trying to reduce its complexity and size in order to provide a minimal failing test case.

It's the same work we do when opening a bug report for someone else's code: we try to find a minimal combination that triggers the bug in order to throw away all unnecessary details that would slow down fixing it.

So in property-based testing the [2, 3, 5, 6, 8, 9, 1, 3, 6, 7, 8, 9] can probably be shrinked to [2, 3, 5, 6, 8, 9, 1, 3, 6, 7, 8] and maybe up to [1, 0], depending on the bug. This process is accomplished by trying to shrink all the random values generated, which in our case were the length of the array and the values contained.

Testing the language

So here's some code I expect to work:
This function creates a PHP DateTime instance using the native datetime extension, which is a standard for the PHP world. It starts from an year and a day number ranging from 0 to 364 (or 365) and it build a DateTime pointing to the midnight of that particular day.

Here is a property-based test for this function:
We generate two random integers in the [0. 364] range, and test that the difference in seconds of the two generated DateTime objects is equal to 86400 seconds multiplied by the number of the days passed between the two selected dates. A property of the input (distance) is maintained over the output in a different form (seconds instead of days).

Surprisingly, this test fails with the following message: what happened is we triggered a bug of the DateTime object while creating it with a particular combination of format and timezone. The net effect of this bug could have been that our financial reports (telling daily revenue) would have started showing the wrong numbers starting from February 29th of the next year.

Notice that the input is shrinked to the simplest possible values that trigger the problem: January 1st on one value and March 1st on the other.
Eventually we found a easy work around, as with a couple more lines of code we can avoid this behavior. We could do that only after discovering the bug of course.

In conclusion

Testing an application is a necessary burden for catching defects early and fix them with an acceptable cost instead of letting them run wild on real users. Property-based testing pushes automation also in the generation of inputs for the System Under Test and in the verification of results, hoping to lower the maintanance cost while increasing coverage at the same time.

Given the domain complexity handled by the datetime extension, it's doing a fantastic job and it's being developed by very competent programmers. Nevertheless, if they can slip in bugs I trust that my own code will, too. Property-based testing is an additional tool that can work side by side with example-based testing to uncover problems in our projects.

We named the property-based PHPUnit extension after Eris, the Greek goddess of chaos, since serious testing means attacking your code and the platform it is built on in the attempt of breaking it before someone else does.

References

Thursday, April 07, 2011

The Shower Methodology and Kanban

I'm still reading (really slowly, in order to absorb informations better) Test-Driven Development by example by Kent Beck.The author cites Paul Ungar's Shower Methodology for writing code:
  • If you know what to, type it.
  • If you don't know what to type, go take a shower.
 Many teams would be happier, more productive, and smell a whole lot better if they took his advice. -- TDD by Example
The shower is indeed the place where many difficult problems are solved. When you have a difficult problem, and it becomes and stay your top priority, your brain daemons (background processes) will work on it for you, and present a fresh solution in an unexpected moment, when you stumble on the problem in an unfamiliar environment such as the shower. When you are parking your car, or walking, or showering, these processes will leverage your free CPU.
Sometimes raising money becomes your shower top priority:
I realized recently that what one thinks about in the shower in the morning is more important than I'd thought. I knew it was a good time to have ideas. Now I'd go further: now I'd say it's hard to do a really good job on anything you don't think about in the shower. [...] Money matters are particularly likely to become the top idea in your mind. The reason is that they have to be. It's hard to get money. It's not the sort of thing that happens by default. It's not going to happen unless you let it become the thing you think about in the shower. And then you'll make little progress on anything else you'd rather be working on. -- The Top Idea in Your Mind

Test-Driven Development is an extension of Ungar's Shower Methodology. Given a red (failing) test, you'll have to make it pass:
  • If you know what to type, type it: always start from the Obvious Implementation if you know what it is.
  • If you don't know how to achieve the result, Fake It: return 0, return 4 and other hard-coded test-specific production code are ubiquitous as TDD starting points.
  • If you still can't generalize after faking the response, try Triangulation: write another test which feeds the system other values and expects a different response. This test, when passing, will ensure there is no hard-coding anymore.
  • If with triangulation you still don't know how to go on, take a Shower.

For example, given the test for extracting the square root of 2:
$this->assertEquals(1.4142..., sqrt(2));
I would code an Obvious Implementation for sqrt(), if I already know the algorithm.
If I'm unsure, I would insert return 1.4142 to get a green bar initially, and then go on writing the algorithm.
If I do not know the algorithm at all, I will insert another test for sqrt(3) to triangulate it (even more than one test if it's the case).
If now I wonder what the algorithm is and I have no idea on how to go on, I will take a shower and think about it.

Disclaimers: TDD in this version is a methodology for implementing a single feature (it doesn't cover prioritization, or estimation, or everything else). It acts as a low level of abstraction, which can become higher if you can write end-to-end and functional tests.
Note also that taking a shower may be metaphorical: you can go work on another project, or another component, or to a meeting, or google for some resource on algorithms and data structures.

Our Kanban board
After all this talking about breaks, the comparison that does not always fit is with Kanban and Work-In-Progress limits. If you have to build a car, indeed you will achieve a very short lead time if you limit the buckets of semi-finished parts: there will be less inventory to transport and store, they will be exchanged more frequently and so on...
If you have to develop software, well, it depends: if you always perfectly know what to type, you can place a WIP limit of one or two user stories and work only on one feature at the time. Scrum and every Agile methodology does exactly this with iterations; Kanban does it at a finer level by limiting the tasks that can be moved forward in each phase (analysis/development/testing/deployment/...).
If I am on a PHP web application, Usually I perfectly know what to type: no problem with WIP limits.
Yet if learning is involved, you may juggle different stories and tasks in the same time period, working for example for one day on each, rotating them. I am tackling a difficult computer vision project where I have to solve problems that range from tracking vehicles in a video to estimate their positions and understand if they will collide under certain conditions. I'm putting in it 4 hours a week: there's no way I will be able to do more due to the research and experiments involved (half of the time I do not know how to go on; and it's normal.) Multitasking is the only way to go if I do not want to lose the other 36 work week hours.
So if I had an hard WIP limit on the projects I can tackle, I would be screwed. You know what works with very large WIP limits? Universities. Normally in Italy you can have 6 courses at the same time. If you try to do one course at the time (20 hours a week for three weeks), you will shoot yourself. Formally, there are almost no limits in the engineering faculties: you can complete your studies following the order you prefer.

Thus I think WIP limits are important as they avoid attacking too many things at the same time, and never complete any. Yet if creativity is involved, shuffling projects and go taking a shower when you need it will help you more.

I went for a shower after writing a draft of this article, and I thought also about the analogy of reading books, which is an example of where Kanban is really useful (summing it up: don't buy books if you do not already read all the ones from the last order.) In the cases of user stories, car parts or books we have a set of items which is useless until it goes through all the stages: a user story is deployed, a car part is on the road, a book is ordered, unpackaged and read. You don't get value from a still wrapped book sitting on your shelf, a story you can't deploy yet or an engine not mounted on a car.
With university, it's beneficial to have related courses taken at the same time instead of serially: you can often apply in practice a concept coming from another course, or compare different approaches (mathematical one vs. physics one vs. the engineer's attitude to linearize and model everything as a Gaussian; or the operations researcher attitude towards a problem vs. the computer scientist goal to find the best data structure to solve it).
With research projects like the computer vision one, the end result is unclear and there are no subparts that can be defined earlier. That's how it works in scientific research. I often don't have user story to transport from one side to the other of the board: I have challenges to overcome with creative thinking, and creativity is not a very repeatable, optimizable process.

Note that there is always a bit of creativity in every software project: that's what makes it fun.

Monday, April 04, 2011

Kent Beck on Singletons

Test Driven Development: By ExampleThis is an excerpt from Test-Driven Development By Example, the book by Kent Beck which introduced a first formalized version of TDD to the world.
Singleton is cited as one of the most famous design patterns, along with Null Object and Composite:
How do you provide global variables in languages without global variables? Don't. Your programs will thank you for taking the time to think about design instead. 
That's it, that's the whole Singleton chapter. First printing: October 2002.

There's also a more recent (re)tweet:
RT @: Someone (who?) gave me a good pattern tip at : don't say "singleton", say "globalton" instead. Nice one!

@natpryce is one of the two authors of Growing Object-Oriented Software, guided by tests.

Sunday, March 27, 2011

Weekly roundup: going to the roots of TDD

I'm reading Test-Driven Development by example by Kent Beck, the original book where TDD was presented to the public. I'm getting many insights on the Red-Green-Refactor process, but one thing is becoming clear (and it is also explicitly stated): TDD is not a substitute for design choices. It gives you a quick feedback about the current code design, its testability and coupling; but choosing metaphors, names and patterns is up to you.
Unless you were once bitten by a radioactive Kent Beck, your design-sense should be nurtured with practice, like any other skill.

Here are my articles published this week, some of which regard testing as well.
Practical PHP Testing Patterns: Configurable Test Double is the main method for building Test Doubles.
How to enrich lawyers explains the goals of the patent system, and its many issues.
Practical PHP Testing Patterns: Hard-Coded Test Double is a type of Test Double written by hand, and very explicative.
Web Workers, for a responsive JavaScript application is a running example of this HTML 5 innovation.

Wednesday, August 18, 2010

Refactoring PHPUnit's getMock()

Not an actual refactoring, but at least the introduction of a layer of indirection, a Parameter object, called PHPUnit_Framework_MockSpecification. I have already written the patch in a branch of my github repository. They are actually two independent patches, since PHPUnit core and the mocking component are in two separate repositories:
http://github.com/giorgiosironi/phpunit/commit/c7d62874ff9c1ed6f520e98cab2568c9bb933ec6
http://github.com/giorgiosironi/phpunit-mock-objects/blob/mock-specification/PHPUnit/Framework/MockSpecification.php
http://github.com/giorgiosironi/phpunit-mock-objects/blob/mock-specification/Tests/MockSpecificationTest.php
All functionalities were Test-Driven Developed.

Use cases
The current API of getMock(), the Facade for the mocking library, actually prescribes 7 parameters. Most of them are optional, like in use case (a):
$this->getMock('MyClass');
But if you want to specify an uncommon parameter, you have to include the previous ones, and hunt around for their default values, praying that you will get them right and insert the boolean or empty values in the correct order, like in (b):
return $this->getMock('MyClass', array(), array(), '', false);
In some cases (c):
$this->getMock('MyClass', array(), array(), '', true, true, false);
A Specification objectBuilder pattern, which I intend to propose as a feature request after getting some feedback from the community, will aid some of these use cases. For example a) remains the same: there is no need to complicate the API here.
$this->getMock('MyClass');
For case b):
$this->getMockSpecification('MyClass')
     ->disableOriginalConstructor()
     ->getMock();
For case c):
$this->getMockSpecification('MyClass')
     ->disableAutoload()
     ->getMock();

State of development
I have currently implemented support for 6/7 of the getMock parameters in the MockSpecification object (only the autoload-related parameter is missing). This solution is an instance of the Builder pattern (I need a new name for MockSpecification, which started out as a parameter object but then acquired a getMock() method for a faster access to the created object).
Once the mock is created, it behaves exactly like an ordinary mock: MockSpecification calls getMock() internally.
This would be a totally backward compatible change, since it only adds a new way to creating a mock.

What I want from you
Any feedback, from glitches in the code to better names for the API methods and the class itself. I guess PHPUnit_Framework_Mock_MockBuilder can be the right name. Once tidied up the code, I'll open a ticket for a feature request on PHPUnit's trac asking to assess it and merge in the master repository.

Saturday, June 26, 2010

Weekly roundup: Chansonnier is ready

This week I've completed the last user story (search term highlighting) on Chansonnier, my thesis-related project on multimedia search. Now I'm reviewing my thesis document with the goal of graduating in July and return to the PHP world.

Here are my original articles for this week.

DZone
Practical PHP Patterns: Single Table Inheritance
Lower your bar in Test-Driven Development
Practical PHP Patterns: Class Table Inheritance
The refactoring breakthrough on a CoffeeMachine, a post which gained little attention but that presents my approach to Test-Driven Development and refactoring on a little sample project from the ground up. If you wanna see how I work with TDD, this post also points to the related repository on github.

php|architect
Open source life style

Tuesday, May 04, 2010

Small steps

Today I was working with a Java framework which runs on top of OSGi (another framework, and yes, Java is verbose even from the platform stack point of view.)
After having prepared a (hopefully) failing acceptance test which used httpunit to extract the content of a dynamic page and verify that the world "Hello" is contained in it, I was ready to run the test, see the assertion failing and start writing our beloved production code.
Unfortunately, the test failed not because of the assertion, but because the JUnit Plugin runner, which takes a JUnit test and run it over a configured OSGi framework, was saying "No tests found." How that was possible?

When tests that should drive the development leave you without a clue on what is happening, chances are that you are taking big steps when you should walk carefully. I was taking big steps because it takes two minutes to run such an acceptance test due to all the infrastructure noise, but I'm not an expert in OSGi applications and I should have taken smaller steps towards my goal of a failing test. The same is true for production code: if I can't get a green bar maybe my failing tests are not fine-grained enough.

Thus I run a git reset and perform the following baby steps to build confidence:
  • create an empty bundle (jargon for package), and write an empty test in it. Run and see Warning: no assertions, but nothing explodes.
  • Add a test method with a assertTrue(true) call. Run, and nothing explodes still.
  • Add httpunit in lib/ and set it up with the Bundle-ClassPath directive, which basically says where the runtime can find the library JARs in the bundle. 

Ok, it was that. After a quick search on Google, I found out that I was specifying the classpath as I've always done via command line or ant scripts:
Bundle-ClassPath: .:lib/httpunit.jar
while OSGi has a different opinion of classpaths:
Bundle-ClassPath: ., lib/httpunit.jar
So I lost even the current directory (.) from the classpath when introducing the first, malformed directive.

After having located the problem with a test-first approach, I was able to (slowly) run my red test and return writing production code.
Automated testing and incremental development save the day again - imagine what would have happened if I had to debug this mess manually, with a framework that takes some minutes to start, and no idea of where the error was...

Friday, April 30, 2010

Zen-Driven Development, part 1

Inspired by Eric S. Raymond's Unix Koans.
 
Long time ago, a student wanted to learn Test-Driven Development. Thus, he went to the Great Master to learn the ways of test-first design.
The student said to the Master "How can I learn TDD, this new methodology that would fix my broken designs?"
The master answered "If you want answers from me, I cannot help."
But the student did not understand.

The day after that, the student came back to the Great Master.
He said "Master, I am humile and eager to learn. Can you tell me how can I employ Test-Driven Development in my projects? I have so much legacy code to tame... I want to be Agile."
And the Master "Again, I do not have answers."

The third day, the student came back discouraged.
"Master, I do not want answers. Just give me a little clue, since in three days I have not written a single line of code. I want to be a TDDer."
"Listen to me, for a great truth is being revealed to you, without any certification course."
The student looked at the Master impatiently. The Master continued:
"You told me you want to learn TDD. But TDD does not start working on a problem by producing its answer. It starts from defining the problem, posing a question. Only when there is a clear, formal question defined you can verify you have answered it when the time comes."
Then there was a bit of silence, as the student nodded in agreement.
"Are you able to write a wget clone by using TDD?" the Great Master asked.
"Of course no, master..."
"Then we get a red bar."
And then, the student was enlightened.

Monday, March 29, 2010

The TDD checklist (Red-Green-Refactor in detail)

I have written up a checklist to use for unit-level Test-Driven Development, to make sure I do not skip steps while writing code, at a very low level of the development process. Ideally I will soon internalize this process to the point that I would recognize smells as soon as they show up the first time.
This checklist is also applicable to the outer cycle of Acceptance TDD, but the Green part becomes much longer and it comprehends writing other tests. Ignore this paragraph if this get you confused.

TDD is described by a basic red-green-refactor cycle, constantly repeatead to add new features or fix bugs. I do not want to descend too much in object-oriented design in this post as you may prefer different techniques than me, so I will insist on the best practices to apply as soon as possible in the development of tests and production code. The checklist is written in the form of questions we should ask ourselves while going through the different phases, and that are often overlooked for the perceived simplicity of this cycle.

Red
The development of every new feature should start with a failing test.
  • Have you checked in the code in your remote or local repository? In case the code breaks, a revert is faster than a rewrite.
  • Have you already written some production code? If so, comment it or (best) delete it to not be implicitly tied to an Api while writing the test.
  • Have you chosen the right unit to expand? The modified class should be the one that remains more cohesive after the change, and often in new classes should be introduced instead of accomodating functionalites in existing ones.
  • Does the test fail? If not, rewrite the test to expose the lack of functionality.
  • Does a subset of the test already fail? Is so, you can remove the surplus part of the test, avoiding verbosity; it can come back in different test methods.
  • Does the test prescribe overly specific assertions or expectations? If so, lessen the mock expectations by not checking method calls order or how many times a method is called; improve the assertions by substituting equality matches with matches over properties of the result object.
  • Does the test name describe its intent? Make sure it is not tied to implementation details and works as low-level documentation.
  • How much can you change in an hypothetical implementation without breaking the test (making it brittle)?
  • Is the failure message expressive about what is broken? Make sure it describes where the failing functionality resides, highlighting the right location if it breaks in the future.
  • Are magic numbers and strings expressed as constants? Is there repeated code? Test code refactoring is easy when done early and while a test fails, since in this paradigm it is more important to keep it failing then to keep it passing.
Green
Enough production code should be written to make the test pass.
  • Does the production code make the test pass? (Plainly obvious)
  • Does a subset of the production code make the test pass? If so, you can comment or (best) remove the unnecessary production code. Any more lines you write are untested lines you'll have to read and maintain in the future.
  • Every other specific action will be taken in the Refactor phase.
Refactor
Improve the structure of the code to ease future changes and maintenance.
  • Does repeated code exist in the current class?
  • Is the name of the class under test appropriate?
  • Do the public and protected method names describe their intent? Are they readable? Rename refactorings are between the most powerful ones.
  • Does repeated code exist in different classes? Is there a missing domain concept? You can extract abstract classes or refactor towards composition. At this high-level the refactoring should be also applied to the unit tests, and there are many orthogonal techniques you can apply so I won't describe them all here.
Feel free to add insights and items on the list in the comments. I value very much feedback from other TDDers.

Wednesday, March 10, 2010

Acceptance Test-Driven Development

I am halfway through reading Growing object-oriented software, guided by tests, a book that teaches Test-Driven Development in a Java environment. A review will come soon, since the process described in this work is really language-agnostic and interesting also for php developers.
However, the book's authors introduce a very productive practice, which consists in a double cycle of TDD:
  • a longer cycle, where you write acceptance (aka end-to-end) tests, deriving them from the user stories or formal requirements, and make them pass;
  • a shorter cycle contained in the first, which happens in the phase when an acceptance test is red: you write unit tests and make them pass until the related acceptance test does not fail anymore.

This approach is an implementation of Acceptance Test-Driven Development, and in particular makes you write several unit tests for every acceptance test (read for every feature) you want to add. Acceptance testing gives immediate feedback on the application's external qualities: simplicity of use and setup, consistency of the interface. At the same time, unit testing gives feedback on the internal qualities: decoupling, cohesion, encapsulation.
When I started employing the double cycle, getting in the zone suddenly became less difficult. The advantages of the TDD process were for the first time applied to the whole process, from the requirements formalization to the end of a feature's development:
  • test-first paradigm. By the end of the development phase, regression tests will be already in place, and the production code will be forced to be testable.
  • The definition of "done" is very clear (the acceptance test passes), and you are more likely to write only the mandatory code to get a green bar at the higher level.
  • measuring progress is easy: the number of acceptance tests that are satisfied (weighted by points). You can even write a set of acceptance tests for the whole iteration in advance and keep them in a separate suite, moving them in the main suite when they start to pass.
To be a bit more specific, the php technologies I use for the two cycles of development are Zend_Test for the acceptance tests suite and plain old PHPUnit test cases for the unit tests one.
Zend_Test is an extension to PHPUnit that lets me define a contract for the http interface of a Zend Framework application, assert redirects, check parts of the html response via css selectors, and even falsify request headers to simulate ajax requests. The unit tests usually have no dependencies on a particular infrastructure, so PHPUnit itself is a powerful enough tool to write them with.
By the way, triting an automated acceptance test suite is more difficult than writing unit tests, as there is more infrastructure that gets in the way and a large amount of details that may render the tests brittle. Fortunately Zend_Test takes care of almost all the infrastructure (aside from the database, which I reset in the setUp phase of test cases), and acceptance tests code can and should be refactored to avoid duplication of the implementation details. For instance, Css selectors used to assert on parts of the html response can be stored in constants with an expressive name, and the request creation can be wrapped in helper methods that are composed in actual test ones. Also custom made assertions are helpful in keeping the noise to a minimum.

I hope this technique will be useful for all test-infected developers. It certainly enhanced my productivity and will to get a green bar. :)

Wednesday, February 10, 2010

Testing private members

Yesterday, Sebastian Bergmann, the author of PHPUnit, posted his response to a question he is asked frequently, How do I test private members of a class?
He summarizes the ways to access private fields and methods of an object from a PHPUnit test case, and he concludes that being able to test them does not mean it is a good thing. Today I am going to explain why testing private methods explicitly is considered a bad practice.

Why do we limit the scope of a method to private or protected to begin with? To be able to subsequently refactor the code and change the signature or the behavior of the method accordingly to new requirements or what we have learned about the problem domain.
The same reasoning is even more valid for field references, which cannot encapsulate a computation and are simply stored variables. I haven't created public fields in production code for years.
Thus the first reason is: a test that exercises a private member couples the private member to code that is external to the system under test. This means you cannot safely delete or modify a private method simply by modifying a class source file: you will have to update the test even if the external behavior of the SUT did not change.

Sometimes you find a private method which contains purposeful logic, and you may want to cover it with specific testing. If this is the case, I suggest to move such method in an extracted class whose instance is stored as a private reference. This way you'll be able to test both the extracted class and the original one, maybe even mocking out the private method in the latter's unit tests. The abstraction provided by the original class is left untouched.
This solution is useful particularly when testing a private method becomes simpler than testing a public one of the same class; it is the sign that another interface is needed between the class and its private member. You're establishing a contract anyway, by writing a test for it: so why do not make this contract explicit and give it citizenship with a class?
The Single Responsibility Principle is the most abstract and the most overlooked of all object-oriented techniques.

Now let's tackle the same problem in the contest of Test-Driven Development. Remember what TDD means: writing code only to satisfy a unit test, while not being allowed to write more code than the really mandatory lines to get a green bar.
How do you get to write a method if you're doing TDD? There are two possible cases:
  • the method is written to make a test pass directly; only public methods can serve this purpose if you do not let test code tinker with class internals.
  • The method is written as a consequence of internal refactoring; but if you're refactoring, there are tests that cover the interested functionalities, so the method is tested anyway via public methods.
Thus the original question is similar to How do I test an abstract class? Since an abstract class can be possibly created only by extracting a superclass from well-tested concrete classes, it should not be tested as well as private methods should not be tested, because they are exercised by definitions by subclasses and public entities. If they weren't exercised, we would have simply thrown them away as unreachable code. If they need more exercising code (maybe they are not in shape :), they should declare a public contract and reside on an external class.
The moral of this analysis is: Test-Driven Development once again saves the day and makes sure our code is covered; unit testing becomes really hard only if you do not write tests first.

Sunday, February 07, 2010

Test suites and php namespaces

Php namespaces, introduced with the 5.3 release, are a great tool to stop writing very long class names. Importing class names via use statements makes you able to refer to classes via their base name, for example by writing:
use NakedPhp\MetaModel\NakedObject;
you will be able to use the name NakedObject in method definitions and instantiations in the rest of the script.
In test code, however, you will often have to import the classes under test and the involved abstractions to define some stubs. If the primary test case class for NakedBareObject is NakedPhp\Tests\ProgModel\NakedBareObjectTest, an use statement in its source file such as:
use NakedPhp\ProgModel\NakedBareObject;
is mandatory.

My suggestion is to organize code in parallel class hierarchies for test case classes and production classes, so that the test suite's classes are not in the same folders as their SUTs, but they reside in the same namespace at runtime. This is a diffused practice in the JUnit world and it is even listed in the JUnit faq.
Consider as an example the NakedPhp directory structure:
http://nakedphp.svn.sourceforge.net/viewvc/nakedphp/trunk/?pathrev=137
library/ and tests/ are the two folders that contain production code and test cases in parallel hierarchies. Autoloading works simply by adding to the include_path both directories.
The test case classes have the suffix Test added to the name. The test case class for NakedPhp\ProgModel\NakedBareObject is NakedPhp\ProgModel\NakedBareObjectTest.
The basic assumption of this directory structure is thinking of namespaces as packages, or reusable modules, whose dependencies should be limited as much as possible. Considering the NakedPhp repository, I am refactoring the original NakedPhp\Metadata namespace, splitting it in two parts: NakedPhp\MetaModel and NakedPhp\ProgModel, with the latter's classes having dependencies on the former, which contains primarily interfaces. I am also moving the classes which disturb the cohesion of these two namespaces in other ones which already depends on NakedPhp\MetaModel: high cohesion of single software modules is obtained by keeping together strongly coupled classes, so that changes in one of them do not propagate all over the application.

Here are some advantages of the parallel hierarchies paradigm:
  • when you're testing the SUT you don't have to import it, since the two classes are in the same namespace (but in different folders, so test cases do not clutter your production code directories.)
  • when you're referencing classes or interfaces from the same namespace, treated here as a package, you still do not have to import them. This case will be very frequent as good engineered classes do not have different responsibilities but delegate part of their operations to collaborators.
  • when you're using classes from another namespace, this is the signal that you are establishing coupling to that namespace. This is not necessarily bad. Use statements become not a boring and repetitive declaration to write, but the signpost of an external dependency towards another module of your application. Mutual or unnecessary dependencies between namespaces are smells that are thus noticed quickly.

Monday, December 28, 2009

Practical Php Testing exercises

As you probably know there is a Creative Commons licensed ebook available on this blog, Practical Php Testing.
Tomaž Muraus wrote to me yesterday about solving the TDD exercises contained in the various chapters:
I had some time during the past few days so I read your book and solved the exercises found in the book.
I'm pretty sure not all of my solutions are the best and some could probably be improved / changed so I decided to create a Github repository with my solutions (http://github.com/Kami/practical-php-testing-exercise-solutions) so others can fork it and improve / refactor my solutions.
I hope you can find these examples useful, but try not to read a solution before actually trying to solve an exercise. I have not proof read this code but it seems that its quality is good. There is always room for improvement, especially in the stubs section of the tests, and in refactoring of the production code.

Tuesday, December 15, 2009

Learning how to refactor

Refactoring is the process of improving the design and the flow of existing, working code by applying common patterns, like extracting a superclass or a method, or even introducing new classes as well as deleting existing ones.
Probably if you are here you have already experienced the refactoring process, but I want to clarify the common iterative method I use, to get feedback and being helpful to developers who are naive in this practice.

This is the general process to learn how to refactor code, which wraps the basic refactoring cycle.
Step 1: get the book Refactoring: Improving the Design of Existing Code by Martin Fowler (a classic) or a refactoring catalogue on Wikipedia or Fowler's website. In the book or in a similar guide, there are two lists which are very boring if read sequentially: smells and refactorings. Smells are situations that arise in an architecture, while refactorings are the standard solutions to eliminate smells. It is annoying to keep something that smells in your office.
Since it is very boring to read the Refactoring book if you have even a small experience with the practice, the best way to extract all Fowler's knowledge is to apply it directly.
Step 2: For S in 'smells':
  • Read about S; understand what is the problem behind a practice that you may have used without worries.
  • Loof for S in one of your personal projects or where you have commit access and responsibility for the code base; get convinced that this smell should be eliminated. If you are not convinced, stop here this iteration and go to the next smell; your existing solution can be pragmatically correct in the context of your style or in your architecture. Note that there are no absolute reference points and refactorings often come in pairs: it is up to you to choose if refactor in a direction or in the opposite one (Extract Method or Inline Method?)
  • Find an appropriate refactoring R; there are multiple solutions that can eliminate a smell. Be consistent in your choice in different places.
  • Make sure there are unit tests for the code you're going to edit. No further action should be taken before you are sure functionality is preserved. This is the answer to the question "Why change something that works?"... Because it will still work, but much better.
  • Apply R in small steps, running focused tests every time to ensure you have not break anything.
  • Once the refactoring is complete, run the entire test suite to find out if anything is not working. Note that failures in points distant from refactored code constitute a smell too: they are a symptom of coupling.
  • svn diff will calculate a picture of your modifications; ensure that debug statements or workarounds are not in place anymore.
  • svn commit (or git equivalent commands) pushes your improvements to the repository. Using version control is also fundamental in case you get in a not recoverable state: svn revert -R . is the time machine button (no, Apple has nothing to do with it) to restore the original code.
The goal of learning various refactoring techniques is to easily see smells in the future, to improve the efficiency of the Refactor phase in the Red-Green-Refactor cycle. Your bricks (classes) are very malleable when fresh, but when they solidifiy it becomes harder to add further modifications: it is good to refactor as much as possible just as you have finished adding code for functional purposes.

Saturday, December 12, 2009

Saturday question: testing in .NET

A reader wrote to me asking resources for learning how to implement Test-Driven Development in an .NET environment:
Please pardon me for my unsolicited email, but I saw your blog and I believe that you are one of the best in the software community. My name is [omissis], and I'm a C#/ASP.NET programmer from the Philippines, but I really want to learn and understand Unit Testing and TDD the right way. I didn't take Computer Science or a similar course in college. I really want to learn software design and development, on how to develop an application from ground-up using TDD. I hope you can give me advices, since I'm not able to afford a good book.
I am no particular expert in C# since I mostly work in php. As you may know, I have written a free CreativeCommons-licensed ebook on php applications testing.
For the .Net case, if you are a beginner, there is a book I reviewed which is a good starting point: The Art Of Unit Testing, which has lots of .NET examples included.
It costs $26 on Amazon now, which you can consider an investment since the knowledge contained could make you earn more in the future. It is a very complete book.
You can also obtain the book for free via other means, such as public libraries. I personally use a lot my university's library to look for information in technical books like Design Patterns when I am not going to buy a copy at the moment, as they are not diffused in normal libraries. You already pay for libraries with your taxes so you'd better take advantage of them.

Once you have the basis, the best way to improve is practicing... Someone said that a developer becomes proficient in unit testing after having written 1500 tests.
For general advice, you may also follow this blog and the Google Testing one, although they are focused on technologies different from .NET.
The principles of testable and decoupled design are the same in all object-oriented languages, and the distinction between C# and php resides in how and when an application object graph is created.
I hope you can find this references useful to start your journey.

Thursday, December 10, 2009

Who else wants to have free documentation? A readable test code sample

It's fun to TDD classes for your projects because you try your class as its client will do even before both are written at all: interfaces and abstractions are by far the most important part of an application's design. But often test classes grow, and we should ruthlessly refactor them as we will do with production code. One of the most important factors to consider in test refactoring is preserving or improving readability: unit tests are documentation for the smallest components of an application, its classes. New developers that come in contact with production classes take unit tests as the reference point for understanding what a class is supposed to do and which operations it supports.
To give an example, I will report here an excerpt of a personal project of mine, NakedPhp. This code sample is a test case that seems to me particularly well written.

The NakedPhp framework has a container for entity classes (for instance User, City, Post classes). This container is saved in the session and it should be ported to the database for permanent storage when the user wants to save his work.
This is the context where the system under test, the NakedPhp\Storage\Doctrine class, has to work: it is one of the first infrastructure adapter I am introducing. In the test, User entities are stored in a container and they should be merged with the database basing on their state, which can be:
  • new (not present in db);
  • detached (present in db but totally disconnected from the Orm due to their previous serialization; no proxies are references from a detached object and these entities are not kept in the identity map);
  • removed (present in db, but should be deleted as the user decided so).
The NakedPhpStorage\Doctrine::save() method takes a EntityCollection instance and processes the contained objects bridging the application and the database with the help of the Doctrine 2 EntityManager.

This test class is also an example about how to test your classes which require a database, such as Repository implementations. I usually create throw-away sqlite databases, but Doctrine 2 can port the schema to nearly every platform. Using a fake database allows you to write unit test that run independently from database daemons and without having to mock an EntityManager, which has a very long interface. Classes that calculate bowling game scores are nice but classes that store your data a whole lot more.
Finally, I warn you that this example is still basic and will be expanded during future development of NakedPhp. What I want to show here is where the Test-Driven Development style leads and an example of elimination of code duplication and clutter in a test suite.
<?php
/**
 * Naked Php is a framework that implements the Naked Objects pattern.
 * @copyright Copyright (C) 2009  Giorgio Sironi
 * @license http://www.gnu.org/licenses/lgpl-2.1.txt
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * @category   NakedPhp
 * @package    NakedPhp_Storage
 */

namespace NakedPhp\Storage;
use Doctrine\ORM\UnitOfWork;
use NakedPhp\Mvc\EntityContainer;
use NakedPhp\Stubs\User;

/**
 * Exercise the Doctrine storage driver, which should reflect to the database
 * the changes in entities kept in an EntityCollection.
 */
class DoctrineTest extends \PHPUnit_Framework_TestCase
{
    private $_storage;

    public function setUp()
    {
        $config = new \Doctrine\ORM\Configuration();
        $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
        $config->setProxyDir('/NOTUSED/Proxies');
        $config->setProxyNamespace('StubsProxies');

        $connectionOptions = array(
            'driver' => 'pdo_sqlite',
            'path' => '/var/www/nakedphp/tests/database.sqlite'
        );

        $this->_em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
        $this->_regenerateSchema();

        $this->_storage = new Doctrine($this->_em);
    }

    private function _regenerateSchema()
    {
        $tool = new \Doctrine\ORM\Tools\SchemaTool($this->_em);
        $classes = array(
            $this->_em->getClassMetadata('NakedPhp\Stubs\User')
        );
        $tool->dropSchema($classes);
        $tool->createSchema($classes);
    }

    public function testSavesNewEntities()
    {
        $container = $this->_getContainer(array(
            'Picard' => EntityContainer::STATE_NEW
        ));
        $this->_storage->save($container);

        $this->_assertExistsOne('Picard');
    }

    /**
     * @depends testSavesNewEntities
     */
    public function testSavesIdempotently()
    {
        $container = $this->_getContainer(array(
            'Picard' => EntityContainer::STATE_NEW
        ));
        $this->_storage->save($container);

        $this->_simulateNewPage();
        $this->_storage->save($container);

        $this->_assertExistsOne('Picard');
    }

    public function testSavesUpdatedEntities()
    {
        $picard = $this->_getDetachedUser('Picard');
        $picard->setName('Locutus');
        $container = $this->_getContainer();
        $key = $container->add($picard, EntityContainer::STATE_DETACHED);
        $this->_storage->save($container);

        $this->_assertExistsOne('Locutus');
        $this->_assertNotExists('Picard');
    }

    public function testRemovesPreviouslySavedEntities()
    {
        $picard = $this->_getDetachedUser('Picard');
        $container = $this->_getContainer();

        $key = $container->add($picard, EntityContainer::STATE_REMOVED);
        $this->_storage->save($container);

        $this->_assertNotExists('Picard');
        $this->assertFalse($container->contains($picard));
    }

    private function _getNewUser($name)
    {
        $user = new User();
        $user->setName($name);
        return $user;
    }

    private function _getDetachedUser($name)
    {
        $user = $this->_getNewUser($name);
        $this->_em->persist($user);
        $this->_em->flush();
        $this->_em->detach($user);
        return $user;
    }

    private function _getContainer(array $fixture = array())
    {
        $container = new EntityContainer;
        foreach ($fixture as $name => $state) {
            $user = $this->_getNewUser($name);
            $key = $container->add($user);
            $container->setState($key, $state);
        }
        return $container;
    }

    private function _assertExistsOne($name)
    {
        $this->_howMany($name, 1);
    }

    private function _assertNotExists($name)
    {
        $this->_howMany($name, 0);
    }

    private function _howMany($name, $number)
    {
        $q = $this->_em->createQuery("SELECT COUNT(u._id) FROM NakedPhp\Stubs\User u WHERE u._name = '$name'");
        $result = $q->getSingleScalarResult();
        $this->assertEquals($number, $result, "There are $result instances of $name saved instead of $number.");
    }

    private function _simulateNewPage()
    {
        $this->_em->clear(); // detach all entities
    }
}
Do you have other suggestions to further refactor this code?

Wednesday, December 02, 2009

Practical Php Testing is here


Practical Php Testing, my ebook on testing php applications, is finally here as promised, in the first days of December.
How many times in the last month have you seen a broken screen in the browser? How many times did you have to debug in the browser, by looking at the output, inserting debug statements and breaking redirects? How many times did you perform manual testing, by loading a staging version of your application and tried out different workflows in the browser?
If the answer to these questions is more than very few, it's likely that
you should give automated testing a chance.
This book is aimed to php developers and features the articles from the Practical php testing series, while the other half of it is composed by new content:
  • bonus chapter on TDD theory;
  • a case study on testing a php function;
  • working code samples, some of whom were originally kept on pastebin.com;
  • sets of TDD exercises at the end of each chapter;
  • glossary that substitutes external links to wiki and other posts, to not interrupt your reading with terms lookup.
The book comes for free and is licensed under Creative Commons. This phrase means you are free to copy it and give it to anyone. If you find my work useful and you want to be supportive, you can make a donation with the link on the right menu or with the one provided in the book.

Wednesday, November 25, 2009

Testing ebook upcoming


This is the temporary cover of my upcoming ebook, Practical Php Testing. It is a parody of the famous illustration from the book The Little Prince.
This publication focuses on testing and designing php code, with the aid of the leading tool for test automation, PHPUnit. Testing is a skill which is often neglected by php developers, but testable code inherit many benefits of the good design rules it is forced to observe.

Here is a list of included content:
  • a collection of the articles from the php testing series, adapted to the book format. These articles cover the path from basics such as installing phpunit to advanced features like mocks and code coverage.
  • nicely-formatted working code samples in the form of PHPUnit test cases. I believe teaching by examples is by far more effective than abstract discussions.
  • glossary for must-know terms: it's not cool to consult links while reading a book, so I collect specifical terms at the end of the book.
  • TDD exercises at the end of each chapter, which will help the reader to apply the practices he has just learnt by producing working code, with PHPUnit as the only infrastructure needed. Along with code examples, exercising is the faster way to grow as a tester and programmer.
  • I intend also to include a bonus chapter on Test-Driven Development theory, if there is interest by readers. Practical Php Testing is not a book on TDD, but I think the natural evolution of test-infected programmers brings them to embrace TDD.
The size is now around 50 pages, and the book will be published in the first days of December, with Creative Commons license (subscribe to the feed if you want to be notified). You will be free to produce how much copies you want by any mechanical and electronic means (with correct attribution): printing it, sharing it via BitTorrent, emailing it to your friends are things I actually encourage.
Also let me know if you would enjoy other testing topics to be treated as bonus chapters.

Monday, November 09, 2009

Why I don't like the Bowling Game kata

I am a big fan of Uncle Bob and I think he is a master of object-oriented programming and architecture. However, in my opinion his Bowling Game kata (solution for the bowling game scoring problem) it's not the right example to explain design via Test-Driven Development.
The kata consists in showing how to TDD a Game class which calculates the score for a bowling game basing on the pins rolled by the balls. It is a pure TDD exercise, accomplished by writing one test at the time, making it pass and refactor the Game class before adding a new one. This kata has circulated for long in the blogosphere.
Although it is indeed useful to see a perfect and practical example of testing-first for the naive programmer, I didn't enjoy reading the various slides.

For instance, these are the scoring rules for 10-pin bowling games, extracted from the Kata:
The game consists of 10 frames as shown above. In each frame the player has two opportunities to knock down 10 pins. The score for the frame is the total number of pins knocked down, plus bonuses for strikes and spares.A spare is when the player knocks down all 10 pins in two tries. The bonus for that frame is the number of pins knocked down by the next roll. So in frame 3 above, the score is 10 (the total number knocked down) plus a bonus of 5 (the number of pins knocked down on the next roll). A strike is when the player knocks down all 10 pins on his first try. The bonus for that frame is the value of the next two balls rolled [...].
These are fixed business rules. Once the last test in is place, there is nothing to add to the class since the bowling rules are considered standard. It is perfect now and forever. How many times did you write a class that never changed?
A design is considered good if it accomodates change to the business requirements, and I would have tried to implement different bowling scoring systems to see how the Game class can be modified to pass the new acceptance tests without breaking the existing ones. There is a total of five requirements expressed by the tests and while they are added the code is refined accordingly, but it is more an academic example than a real world situation.
When you propose TDD to fellow programmers it seems reasonable, but the first question that they ask you is How do I test my database application?, not in what order should I put my test helper methods? There are different priorities in learning TDD.

This kata is interesting in the sense that it implements a scientific method by changing one factor at the time in the TDD equation and analyzing the result. You find people that execute the same kata in different languages; with different frameworks; different programming paradigms; and so on.
When the majority of frameworks out there are still using static methods, executing katas sometimes crosses the border of overdesign/gold plating/endless polishing. I learned something from the kata, but it's not rocket science. Why not write a patch to some open source project that you use every day instead of investing time in doing the same thing again and again?

There are many math problems which are perfect for learning a new language: consider for instance writing a function which finds perfect numbers. If I were a computer science professor I would assign these problems to C beginners as they are very handy in having no external dependencies and in being easily solvable.
The limit in such learning methodolody is that only structured programming capabilities are exercised and there are many development patterns which are not necessary for solving math problems, and which will not be implemented by a beginner if not forced. Doing the simplest thing that could possibly work leads a beginner to create a function for calculating perfect numbers, not a class so well-tested in different scenarios. The same is true for calculating a bowling game score.
The kata is a very narrow case, recalled when you test a class with no dependencies, no lifecycle problems and with the smallest Api you will never encounter.
Before reading the kata I was excited because I was going to learn how Uncle Bob works. But the demonstration is in fact very basic. I would have preferred to see how he deals with interfaces design, legacy code refactoring, collaborators extraction when classes grow.

Wednesday, November 04, 2009

Testing and constructors

During unit tests preparation you often have to modify your design to simplify the test code. Design for testability is one of the good things about Test-Driven Development and more in generally of unit testing (and with TDD you will not modify your code to allow easier testing but you will write it to do so). A testable design is decoupled and maintainable and in the long run you will get only advantages. With in the long run I intend next week.
One of the pillars of design for testability, which is listed also in the Google guide for code reviewers, is to have constructors that do not contain logic or method calls. I will explain the reasons behind this choice with an example, but let me say that to reduce dependencies it is natural for a class to avoid making assumptions on the external environment, performing things like creating new objects. Separating the business responsibility of a class from the one of wiring itself to other objects is necessary.

As always, the example is in php as there is a great need for good object-oriented programming in this particular field.
class NakedEntity
{
    protected $_entity;
    protected $_class;

    public function __construct($entity = null, NakedEntityClass $class = null)
    {
        $this->_entity = $entity;
        $this->_class = $class;
    }

    public function getState()
    {
        $state = array();
        foreach ($this->_class->getFields() as $name => $field) {
            $getter = 'get' . ucfirst($name);
            $state[$name] = $this->_wrapped->$getter();
        }
        return $state;
    }

    public function getMethods()
    {
        return $this->_class->getMethods();
    }

    // other methods...
}
I omitted docblocks as they are not relevant in this context.
This class purpose is to act as a container for a domain object and its class metadata. These metadata are kept in its $_class field which is a NakedClass object. The extraction process uses reflection and it is encapsulated in another component that returns instances of NakedClass and NakedEntity. Thus, creating a test-friendly NakedEntity object is simple:
$entity = new NakedEntity(new stdClass, new NakedClass('My_User', $methods));
This code snippet tricks my library classes in believing that a stdClass is a My_User istance, and makes unit tests very simple. For instance the classes that work on the methods metadata can try many different combinations of methods without requiring me to write many My_User and My_Group classes. I should thank my constructor: it does not perform work, but only accepts the collaborators and stores them in private fields. If the constructor of NakedEntity parsed the class code like this:
$user = new My_User();
$entity = new NakedEntity($user); // calling get_class() and then doing a lot of work
I would be stuck with My_User methods and I would have to write a new real class for every different test method and my tests would be slower.

Fortunately there is mocking, and I can substitute NakedEntity instances with mocks. But mocking won't always save me from the work in the constructor, as when testing the very NakedEntity class I will have to wait for all the parsing to finish in every test, while I just want to verify that, given a set of method metadata getMethod() and hasMethod() works well. Why should my classes parse docblocks and annotations to test ten lines of array-related code?
Unit testing also means that the code under test is contained in the NakedEntity class, and I can inject mocks or stubs via the constructor instead of a real entity or a real NakedEntityClass object. Keep in mind also that a stub can be the the real production class if a test-friendly instance can be built and it has not much logic: in other tests I often use the NakedEntity class, and I will continue at least until it grows to contain logic I want to take out of my other unit tests.
Focusing on the NakedEntityTest class instead, if the constructor created objects or did a lot of logic it would be difficult to inject the right stubs as they can get in the way during the costrunctor execution. Also a problem in the constructor would make all the tests fail, making more difficult to locate the problem.
One acceptable practice is to instance only newable objects in the constructor, with little behavior. In php an array is the obvious example of newable, since it is not even an object. Also I considered Spl classes newable as they do not slow down tests and cannot commonly break (at least you cannot break them while maintaining your code).

Note the null defaults that the arguments assume, that allow tests to pass in nulls instead of real objects or mocks. I think this is useful when sometimes a collaborator is not used in mediator objects:
$entity = new NakedEntity(null, $class); // emphasis that the test would
// use the NakedClass collaborator.
$methods = $entity->getMethods();
The contract in the code above says "getMethods() should not assume anything about the $this->_entity property". If getMethods() tries to call a method on a null, the code will explode and the test will fail.
It is responsibility of the factory class to create a valid object by passing in meaningful collaborators instead of nulls, and this responsibility would be exercised in an integration or functional test.

In my opinion this is the perfect constructor for my class:
  • it lets the tests inject collaborators, which could be real instances, mocks or stubs;
  • it does not perform work that should be repeated in every test; it only assigns variables to private or protected fields;
  • it lets the collaborators be null values if they should not be touched during a particular scenario.
I know someone will complain: but now how I can write new NakedEntity(...) to work with an instance? I will have to create all its collaborators. You should not do it. A factory should do it for you, and if you require to do it in the middle of a method, you should ask for a factory in the related constructor.
Do you have some example of constructor difficult to refactor in this way? Feel free to post it on pastebin.com and insert the link in the comments for discussing it.

Featured post

A map metaphor for architectural diagrams

It is a (two-dimension) representation of a pipe. The map is not the territory , but in software engineering terms they are models of it....

Popular posts