Help with TDD

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

Post Reply
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Help with TDD

Post by allspiritseve »

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
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Help with TDD

Post by Christopher »

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?
Which tutorials have you looked at? Which test framework are you using?

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)
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Help with TDD

Post by allspiritseve »

Just basic tutorials such as the logger for SimpleTest (which is the test framework I use).
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Re: Help with TDD

Post by McGruff »

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.

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');
    }
}
 
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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Help with TDD

Post by Maugrim_The_Reaper »

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.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

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.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Help with TDD

Post by allspiritseve »

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.
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:Also on an unrelated note I think calling yourself "small" on your website is shooting yourself in the foot business wise.
I do need to update that site... but depending on who you talk to, being a small business isn't such a bad thing.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

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? )
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Help with TDD

Post by allspiritseve »

jshpro2 wrote:why is mocking your data mapper bad though?
Ah, I thought you meant mocking the db. I must have misunderstood you. Mocking data mappers is fine.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

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.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

McGruff 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.
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 will
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Help with TDD

Post by allspiritseve »

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..
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.

Might want to check out this thread, particularly lastcraft's comment (creator of SimpleTest): http://www.sitepoint.com/forums/showpos ... ostcount=5
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.
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...
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Help with TDD

Post by allspiritseve »

jshpro2 wrote:Isn't that coupling the persistence code to the business logic
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).
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

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?
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Re: Help with TDD

Post by josh »

MVC test framework for Zend, looks promising http://framework.zend.com/wiki/display/ ... astructure :P :P
Post Reply