Help with TDD
Moderator: General Moderators
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Help with TDD
Hello all,
I have just started trying to change my development process to testing first. I am having a bit of trouble though-- I can see how it works with methods that take inputs, and give certain outputs based on that input-- I don't understand how to write tests for methods that maybe return true or false, like method that updates or inputs into a database. How do I test those methods? I keep getting stuck trying to write more tests, and get frustrated with the whole process. Can anyone recommend some good tutorials that might help?
Thanks,
Cory
I have just started trying to change my development process to testing first. I am having a bit of trouble though-- I can see how it works with methods that take inputs, and give certain outputs based on that input-- I don't understand how to write tests for methods that maybe return true or false, like method that updates or inputs into a database. How do I test those methods? I keep getting stuck trying to write more tests, and get frustrated with the whole process. Can anyone recommend some good tutorials that might help?
Thanks,
Cory
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Help with TDD
Which tutorials have you looked at? Which test framework are you using?allspiritseve wrote:I don't understand how to write tests for methods that maybe return true or false, like method that updates or inputs into a database. How do I test those methods?
For the methods you mention, you should check both the return value and that the updated value in the database is what is expected. You may want to Mock the database object so you can check the interaction directly.
(#10850)
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Help with TDD
Just basic tutorials such as the logger for SimpleTest (which is the test framework I use).
Re: Help with TDD
All classes which know how to persist themselves would follow the same sort of outline: create the object, save it, load a new instance, and check the object's state was remembered.
Don't mock the database connection object. You'd have to make assertions about sql arguments passed to the mock but this isn't practical. Use a real database set up and torn down for the tests. More here.
Code: Select all
class MyTestCase extends UnitTestCase {
function setUp() {
...
...
}
function testSaveAndLoad() {
$foo = new Foo(...);
$foo->setBar('some value');
$foo->save();
$foo_2 = new Foo(...);
$this->assertEqual($foo_2->getBar(), 'some value');
}
}
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Re: Help with TDD
http://devzone.zend.com/article/3082-De ... evelopment
BDD article but it illustrates a process you can easily adapt to PHPUnit/SimpleTest with some translation and less pretty code. BDD is often described as part "doing TDD well" before anything else BDD offers becomes useful.
BDD article but it illustrates a process you can easily adapt to PHPUnit/SimpleTest with some translation and less pretty code. BDD is often described as part "doing TDD well" before anything else BDD offers becomes useful.
Re: Help with TDD
If you're testing the data gets persisted, you might inject a mock persistence object and assert that the mock object is being called properly, or assert that the correct SQL was generated by your persistence layer. Also on an unrelated note I think calling yourself "small" on your website is shooting yourself in the foot business wise.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Help with TDD
As others have pointed out, its better not to mock the db... trying to match SQL queries results in very brittle tests, in which a space in the wrong spot could give you a false error. As I've discovered since I started this thread, not mocking the db is the way to go.jshpro2 wrote:If you're testing the data gets persisted, you might inject a mock persistence object and assert that the mock object is being called properly, or assert that the correct SQL was generated by your persistence layer.
I do need to update that site... but depending on who you talk to, being a small business isn't such a bad thing.jshpro2 wrote:Also on an unrelated note I think calling yourself "small" on your website is shooting yourself in the foot business wise.
Re: Help with TDD
Yeah matching generated SQL was bad advice, why is mocking your data mapper bad though? It allows you to mock the persistence layer when you test a model, and mock a model when you test your persistence layer ( right? )
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Help with TDD
Ah, I thought you meant mocking the db. I must have misunderstood you. Mocking data mappers is fine.jshpro2 wrote:why is mocking your data mapper bad though?
Re: Help with TDD
Oh, haha yeah that would be worse than testing the SQL.
On another note should I be testing my controllers? Im finding tons of examples I can apply to writing tests for my models, but not much detailed instruction on testing my views, view helpers themselves, etc..
I'm also torn between Fowler not recommending BDD and Dan North advocating it, perhaps I don't have my brain wrapped around the concept as much as I'd like to think I do. If I have an object that's not hard to set up at all and is actually very basic, for example if I had a product object that is supposed to use a tax object to calculate its prices, that tax objects is all but the very simplest implementation of a strategy pattern. Is there really any reason not to mock that strategy pattern as simple as it is? I'm totally feeling the idea of testing the behavior and not the state, to not lock you into an internal implementation.
If you wrote a test in the product unit test to setPrice(100), then asserted that getPriceWithTax()==106, you might as well not even have a tax object. This is where Fowler just comes along and confuses the crap out of me.
On another note should I be testing my controllers? Im finding tons of examples I can apply to writing tests for my models, but not much detailed instruction on testing my views, view helpers themselves, etc..
I'm also torn between Fowler not recommending BDD and Dan North advocating it, perhaps I don't have my brain wrapped around the concept as much as I'd like to think I do. If I have an object that's not hard to set up at all and is actually very basic, for example if I had a product object that is supposed to use a tax object to calculate its prices, that tax objects is all but the very simplest implementation of a strategy pattern. Is there really any reason not to mock that strategy pattern as simple as it is? I'm totally feeling the idea of testing the behavior and not the state, to not lock you into an internal implementation.
If you wrote a test in the product unit test to setPrice(100), then asserted that getPriceWithTax()==106, you might as well not even have a tax object. This is where Fowler just comes along and confuses the crap out of me.
Re: Help with TDD
Isn't that coupling the persistence code to the business logic, both in the production code and in the tests? Which would be fine if you were using active record, correct? Correct me if I'm wrong which I'm sure you willMcGruff wrote:All classes which know how to persist themselves would follow the same sort of outline: create the object, save it, load a new instance, and check the object's state was remembered.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Help with TDD
Sure, the majority of what you're doing will probably be mocking your models and views and making sure the controller is dispatching to them properly. This is also a great opportunity to take advantage of get/post/session wrappers in order to mock the request.jshpro2 wrote:On another note should I be testing my controllers? Im finding tons of examples I can apply to writing tests for my models, but not much detailed instruction on testing my views, view helpers themselves, etc..
Might want to check out this thread, particularly lastcraft's comment (creator of SimpleTest): http://www.sitepoint.com/forums/showpos ... ostcount=5
I've read a couple of articles on BDD, but I just don't buy the hype yet. TDD is still so new, and its working out pretty well for me so far...jshpro2 wrote:I'm also torn between Fowler not recommending BDD and Dan North advocating it, perhaps I don't have my brain wrapped around the concept as much as I'd like to think I do. If I have an object that's not hard to set up at all and is actually very basic, for example if I had a product object that is supposed to use a tax object to calculate its prices, that tax objects is all but the very simplest implementation of a strategy pattern. Is there really any reason not to mock that strategy pattern as simple as it is? I'm totally feeling the idea of testing the behavior and not the state, to not lock you into an internal implementation. But then Fowler just comes along and confuses the crap out of me.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: Help with TDD
Well, as he said, "all objects that know how to persist themselves", which basically means it is an ActiveRecord. The concept can be applied to gateways and mappers though... create an object, save it using the gateway/mapper, and then use the gateway/mapper to fetch it from the db and compare the two objects to make sure they are the same (I typically pick a property to compare).jshpro2 wrote:Isn't that coupling the persistence code to the business logic
Re: Help with TDD
Well take my product tax calculation example for instance, the product should behave in the same way whether it was using a flat rate calculation strategy or a strategy that represented a non taxable item, yes? If you simply test your inputs and outputs your couple you objects, which is the whole point of TDD, TDD is not just to test your code, you can test without doing TDD, TDD is supposed to help you write a non coupled design, by testing each unit separately, but then Fowler just comes along and lists tons of reasons for not testing behavior and then admits he never tried it. I'm just confused is all
Edit: Hmm.. Just re read the part under "Test Isolation" ( http://www.martinfowler.com/articles/mo ... Stubs.html ) now I understand, basically I should avoid using mocks and use a real object where ever it would make sense to use a real object, correct?
Edit: Hmm.. Just re read the part under "Test Isolation" ( http://www.martinfowler.com/articles/mo ... Stubs.html ) now I understand, basically I should avoid using mocks and use a real object where ever it would make sense to use a real object, correct?