|
From: Noel D. <ma...@mc...> - 2010-12-22 20:01:20
|
Hi
> In particular, I'd like to write some customized assertions, for
> instance
> function assertLoginSuccessful($userName, $passWord)
> {
> $this->setField('username',$userName);
> $this->setField('password',$passWord);
> $this->click('Login');
> return $this->assertText('Login successful!');
> }
You only need to assert that you can login once and therefore
I don't think there is a need for an assertLoginSuccessful method. I'd
just make that a test:
function testCanLogin($userName, $passWord)
{
$this->get(..login page..);
$this->setField('username',$userName);
$this->setField('password',$passWord);
$this->click('Login');
return $this->assertText('Login successful!');
}
When that test has passed, I'd write a login method:
function login($name, $pass) {
$this->get(..login page..);
$this->setField('username',$name);
$this->setField('password',$pass);
$this->click('Login');
}
I'd expect you'll need to login a lot throughout the web test suite.
Anywhere you find you're repeating yourself is probably a sign to
refactor into a custom method. Also, a custom method like this will
make tests clearer and simpler because you don't have to read four
lines of code to get the sense of what's going on. Good tests - and
good code in generally - should try to tell a story. That's all about
hiding complexity behind some well-named methods and classes.
I'd probably end up with a loginAsAdmin() method as well, and any
others I need for different user roles.
> What's the right way to create new assert methods that behave like the
> built-in ones, and also build on the built-in ones?
UNIT TESTS
It's OK to hack up a simple assert method as above but, for anything
non-trivial, the "proper" way to create custom expectations is like
this:
class Something extends SimpleExpectation {
var $test_message = 'oops %s';
function __construct($value, $overlaid_message = '%s') {
parent::__construct($overlaid_message);
$this->_value = $value;
}
function test($compare) {
...
...
}
function testMessage($compare) {
if ($this->test($compare)) {
return 'hurrah! ' .
$this->dumper->describeValue($compare);
} else {
return sprintf(
$this->test_message,
$this->dumper->describeDifference(
$this->_value,
$compare));
}
}
}
An assert method using the Something expectation would look like this:
function assertSomething($value, $compare, $message = '%s') {
return $this->assert(
new Something($value), // expectation object
$compare, // the thing being checked
$message); // optional custom message
}
Note that you can pass a custom message in the constructor. If this
contains an "%s" the framework will also embed the simpletest message.
This set up conforms to normal SimpleTest behaviour - that's important
if other people are using your code. Optional if not. I never seem to
use custom messages myself.
It's usual to pass an "A" value in the constructor and then the "B"
comparison value in the test() method. Sometimes you might have more
bits and pieces to pass in to the expectation object: do it in the
constructor. The test() method expects a single value, ie the second
parameter in an assert() call.
Note that testMessage() can use $this->dumper to describe values and
differences - have a look through the SimpleTest code to see how it's
used.
I'd almost certainly want to test the expectation class itself. A test
framework has to be written to a very high standard. Debugging is
exponentially more difficult if you're not sure about the test code
behaviour.
Is it worth all that effort? Most definitely. I wouldn't think twice
about stopping to rattle off some testing code. Time spent now will be
saved in the future. Whenever I try to cut corners I always regret it
later.
WEB TESTS
I don't think I've ever written a custom expectation class for a web
test (but I do write lots of simple methods like your
assertLoginSuccessful). That makes me wonder if I'm maybe doing
something wrong... Probably we're well-covered already with everything
we need in the exisiting test framework. A web page is a well-known
problem which we can predict in advance but unit tests will throw up
all kinds of things which aren't covered by a basic test framework.
Ask away if you need more help.
Noel
|