PHP Unit Testing without a framework... Possible? Advisable? - php

When one starts searching for PHP unit tests, one usually stumbles upon:
PHPUnit.
SimpleTest.
A plethora of blogs explaining how to use PHPUnit and SimpleTest.
StackOverflow questions about PHPUnit and SimpleTest...
...and I think you get the idea.
I was wondering: How does one go about unit testing with plain ol' PHP? Is that even a wise endeavor?
I suppose I would have to build my own little framework. I'm interested because I want to have a better understanding of what's going on in my unit tests. I'm also interested because I think a lightweight, tailored solution would run my tests faster.
Bonus question: Who's the underdog? Is there a third framework worth looking into (for acedemic purposes)?

Unit testing is basically a set of assertions.
Consider the following PHPUnit test case:
class MyTest extends PHPUnit_Framework_TestCase {
public function testFoo() {
$obj = new My;
$this->assertEquals('bar', $obj->foo());
}
}
You can have a similar test case without using PHPUnit:
class MyTest {
public function testFoo() {
$obj = new My;
assert("$obj->foo() == 'bar'");
}
}
However, by doing it without a framework, you will have to manually create an instance of the test case (MyTest) and call each test method manually (MyTest::testFoo, etc.).
The framework (e.g.: PHPUnit) is nothing more than a set of "helpers" to make it easier and faster: by automatically generating skeleton; with built-in mock objects, command lines scripts, etc.
You can still unit test without a framework, but in the end, you'll probably save more time using one, because after all, that's generally what frameworks are for.

My view would be what's so wrong with the standard wheel (PHPUnit in all probability) that warrants the development of a replacement? After all, Isn't a proven solution the wiser choice in this instance?
Additionally, the output of the standard tools will be easier to use if you ever want to take advantage of a Continuous Integration server further down the line. (You could of course make your own tool output in an identical format, but that leads me back to the "why re-invent the wheel" argument.)

I've used SimpleTest about a year ago and it's very lightweight. There really wasn't much to it except providing you a way to auto-load test packages and assert.
Essentially it included all classes starting with "test" and it would call all methods starting with "test" inside that class. Inside the methods you could assert the results are what you expected.
If you were to build your own framework, I would strongly recommend looking into SimpleTest before. It's very lightweight compared to PHP Unit (if that's what scares you).

You can write tests in any language without a framework, but the code you write that you share in your tests will end up being a kind of mini-framework anyhow.
A good unit testing framework will have the common stuff that you need to make testing easier, such as assertions, mocks, stubs, exception handling and code coverage.
Bonus question: Who's the underdog? Is there a third framework worth looking into (for acedemic purposes)?
There are underdogs in the PHP unit testing space, for example Enhance PHP, which is a unit-testing framework with mocks and stubs built in. It has some advantages over the big players - it has good documentation and is very quick to get started on.

Related

Creating a fake user in Symfony2 for testing purposes

I'm somewhat new to testing in PHP. I've done quite a bit of testing on Rails using Cucumber, RSpec, Capybara and Factory Girl, but I've barely done any testing with PHP.
I'll ask a question about my current challenge in the most general way possible, since I've gone down a few specific paths and been met only with frustration.
I want to write a functional test for signing a user in. What's a good way to create the test user object that I would need in order to try to sign in?
Even more generally, what's the de facto standard for creating test objects in Symfony2? Fixtures? Some kind of factory?
In Ruby, I would use Factory Girl, since it lets you handle any object's dependencies in a clean, DRY way. There seems to be a Factory Girl equivalent in PHP in Phactory, but unfortunately it seems that that tool is not widely used and no longer maintained.
Fixtures on a test environment configuration are probably the way to go!
About the fixtures being application-wide comment, I disagree.
If you were unit testing, maybe that would make a lot of sense.
Functional tests, however, are supposed to be application-wide.
I just write test data builders myself, because there is almost no boilerplate anyway. BTW, Factory Girl is an implementation of that very pattern.
You can find a good discussion of the pattern and a lot of other useful stuff in the Growing Object-Oriented Software, Guided by Tests book.
And I recommend against fixtures, because they are application-wide. Each test better prepare only the data it needs for itself.
I use fixtures for functional tests but i disagree that they are application wide only. Im using it bundle-wide, defined in proper dirs in bundles. On test setup i run console fixtures:load method from proper directory and maybe not best solution but it works good for me. If anyone have better solution i would happily read about it :)

TDD: Test MVC application

I've started from scratch a new application using TDD and PHPUnit. It is going to be a MVC application. I've started my tests from the Model. That was fun and i didn't have too much problems.
Now I want to create my views/models. But the question is: How do I test my controllers? What about views? My controller will use my tested models and my future views.
Thanks.
There are three broad categories of testing for each of the layer in the MVC. The unit tests for models, functional tests for the controllers and the UI testing for the views.
Unit tests are the easiest to write. They are cheap in terms of time and do not require too many dependencies to be stubbed/mocked.
Functional tests on the other hand are a bit expensive compared to an unit test. In a given scenario, if you had covered enough in your application for the models using unit test, you can relax a bit in the functional testing part. However, you should still be having a good code coverage - 100% to be ideal for your controller methods as well.
The last is the UI testing which is the costliest of all tests. You can probably use Selenium for browser based testing and try to automate it with your language. You may have to have a RC sever running in the background to achieve this. But trust me, if you cover the first two parts - unit and functional, this can be made optional if not no.
And it is advised to have a CI - Continious Integration setup with a code coverage utility that gives a trending on the % of code covered through tests.
When you are running the tests , you should be using only the class under test. Other objects should be replaced with mocks or other fake structures.
You do this, because ( for example ) when you write a test for controllers action , you will have provide some values for said action, and then check if the correct data is passed to the view and models.
This is one of the reasons why you should avoid use of global state ( in form of static calls or global variables ) in your code.
Some links you might find useful
The Clean Code Talks - Unit Testing
The Clean Code Talks - Global State and Singletons
The Clean Code Talks - Don't Look For Things!

Should I use CodeIgniter's Unit Testing Class or PHPUnit/TOAST?

I'm looking for a good unit testing for my web development. I'm using CodeIgniter for PHP, and I found this class on CodeIgniter's documentation, so here is my doubt:
Should I use 'Unit Testing Class' to test my code, or is going to be better to use PHPUnit or TOAST? Which is better and why?
I hope someone experienced can help me. Thanks!
In my opinion, I think it's better to use the standard PHPUnit for unit-testing.
Aside from that it has many nice features, your tests will be more consistent and it wont depend on CakePHP's unit testing class.
If in the future you decide that CakePHP does not suite your needs, you'll lose your unit tests. (or lets say, you'll have to migrate them, which is time)
If you are testing code, that depends on CakePHP(Controller, Model, etc), there's no problem to use CakePHP's tests, but for any other case, i think you should bet on the more-popular unit testing suite that can be used in every project (PHPUnit)
Happy testing :)
I haven't done any test with codeignitor's build in unit test class. but it looks like that this class provide only very simple assertion function (maybe it is because of the pursuit of lightweight) and the worst thing is, you have to mess up the testing code with your production code.
For unit test, it offers much more assertion functions, more features: like code coverage, selenium RC...etc. so it can extend your ability to ensure code quality. one more benefit is, it does not depend on any of your framework code, so you can easily migrate.
Unit Testing Class is quite simple test suite. If you need full unit testing of your code use PHPUnit.
Codeigniter has its own unit testing feature
Please go to http://codeigniter.com/user_guide/libraries/unit_testing.html
Thanks

Unit Testing CodeIgniter with Simpletest - very few tests

On our development team, we decided to give Unit Testing a try. We use Simpletest. However, it's been a tough road. After a week, I only have created 1 unit test that tests a certain helper file. That's it. The rest (controllers, models, views, libraries) don't have unit tests yet. And I plan to not test a majority of them. Views, for example, are too trivial to test, so I pass up on testing that. Next, the controllers. I plan my controllers to not do complex stuff, so that it only does passing of information between the models and the views. I'd move those more complex stuff to libraries or helpers.
Now for my questions:
1) Am I doing it wrong? So far, there's nothing more that I can see that can be erroneous so it would need a unit test. Most of the stuff (right now) are just CRUD.
2) Do we really need to unit test controllers? Since a controller's job is just minor processing of data passed between View and Model, I find very little initiative in unit testing it.
3) If I use WebTestCase to test for controllers, would that be still considered a Unit Test? Or is it already an integration test?
4) Suppose you got me to test my controller, how would I test it? As far as I know, CI follows the Front Controller pattern through index.php, so how would I handle (mock?) that?
If you are still open with suggestion to another unit test for CodeIgniter, I suggest you try Toast. I found it easy to use, and not interfere much with my development process.
I only use unit test to test my library, helper, and model. My controller not have much code, only get post and uri parameter, sanitizing it using trim or intval, pass it to library or model, then pass the result to view.
View almost have none code to test, since it display everything to browser. Mostly, it just need css and js debugging.
Model almost always need testing, since it dealing with data. Without unit test, I found it difficult to trace some bug, specially with a complex computation.
Library and helper do a repetitive task, so it need a unit test to make sure the logic in it is doing the work correctly.
I hope this help.
Are you doing something wrong? I don't think so.
Do we really need to unit test controllers? I don't. Maybe I should. Seems like a lot of work, though.
If I use WebTestCase to test for controllers, would that be still considered a Unit Test? Or is it already an integration test? WebTestCase would be an interesting approach to testing controllers if some meaningful output could be detected; for example, detecting that no error has occurred when calling /some/specific/path.
Suppose you got me to test my controller, how would I test it? That's a tough one. You would presumably need to initialize part of the application environment in order to do anything worthwhile.
Most articles/books tell you to define your tests before you start coding. Maybe I've tried that, but I'm usually too impatient. It seems to get in the way of quick prototyping, but maybe defining the unit tests is a way of quick prototyping.
I've found that deciding what to test with PHP is a challenge. I think you have to pick your battles. If it's critical that a method return a value of specific type, then test for that. If a lot of things happen automatically when instantiating an object, you could test for that too.
In general, what I do -- right or wrong -- is get everything working, then create some basic tests and then add tests as needed based on any problems I encounter. The idea is to never have a repeat problem and each test will insure that the application behaves the same through its life-cycle.
As for specifics, I'm using Zend Framework, but it will be similar in CodeIgniter. I also use SimpleTest (but with my own class wrapper). I may or may not unit test models and I have never implemented tests for controllers or views; it's seems like too much work and too little benefit. Most frameworks "fail early" and so issues are typically obvious. But any common library code make for easier targets and bugs here -- especially logic bugs -- are harder to detect. Set up your tests to make sure things work as expected so that your framework-specific code encounters few problems.

Why does PHPUnit insist on doing things the OO way?

At the risk of being flamed... what advantage does enforcing calls to methods rather than functions have in a context where the context is implicit.
Considering that PHP's syntax is so ugly for calling methods why would PHPUnit's creators have enforced its usage?
If the framework had set a global "currentTestCase" object and then transparently associated failed asserts with that object we could be writing:
assertEquals("blah", $text);
as opposed to the equivalent, but verbose:
$this->assertEquals("blah", $text);
What exactly do we get by using OO in this context.
Please enlighten me.
Because PHPUnit is derived from xUnit and that's how xUnit does it.
Why does xUnit do it that way? I'm glad you asked. The original reason, as Robert points out, is that xUnit comes from Smalltalk and was popularized by JUnit in Java. Both are OO-or-nothing languages so they had no choice.
This is not to say there are not other advantages. OO tests can be inherited. This means if you want to test a subclass you can run all the parent's tests and just override the handful of test methods for the behaviors you've changed. This gives you excellent coverage of subclasses without having to duplicate test code.
Its easy to add and override assert methods in PHPUnit. Just subclass PHPUnit_Framework_TestCase, write your own assert methods and have your test classes inherit from your new subclass. You can also write default setup and teardown methods.
Finally, it guarantees that the test framework's methods aren't going to clash with the thing that they're testing. If the test framework just dumped its functions into the test and you wanted to test something that had a setup method... well you're in trouble.
That said, I hear your pain. A big test framework can be annoying and cumbersome and brittle. Perl doesn't use an xUnit style, it uses a procedural style with short test function names. See Test::More for an example. Behind the scenes it does just what you suggested, there's a singleton test instance object which all the functions use. There's also a hybrid procedural assert functions with OO test methods module called Test::Class which does the best of both worlds.
Considering that PHP's syntax is so ugly for calling methods
I guess you don't like the ->. I suggest you learn to live with it. OO PHP is so much nicer than the alternative.
One good reason is that assertXXX as a method name has a high risk for naming clash.
Another one is that it is derived from the xUnit family, which typically deals with object-oriented languages - Smalltalk initially. This makes it easier to related yourself to your "siblings" from e.g. Java and Ruby.
Not a direct answer, but as of PHPUnit 3.5, you do not have to write $this-> anymore. PHPUnit 3.5 added a function library for Assertions, which you have to include
require_once 'PHPUnit/Framework/Assert/Functions.php';
Then you can do
assertEquals('foo', $bar);
See Sebastian Bergmann's Blog post about it
http://sebastian-bergmann.de/archives/896-PHPUnit-3.5-Less-this-Required.html#content
Having the test cases in class-methods saves work for PHPUnit. Due to lack of built-in intelligence PHPUnit couldn't find or handle pure test functions. Only having to recognize the ->assert*() messages -in a simple boolean chain- again saves processing logic (for PHPUnit, not the test case author). It's all syntactic salt that saves overhead from the PHPUnit/SimpleTest point of view.
It wouldn't be a technical problem to capture error/warning messages, exceptions or recognize PHPs native assert() statement. It's not done because a difficult API looks more enterprisey.

Categories