SitePoint Sponsor

User Tag List

Results 1 to 25 of 25

Hybrid View

  1. #1
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Simpletest - setting variables in a class

    Not really to do with "PHP Application Design", but the other Simpletest questions seem to end up here. Please move this if it's in the wrong place.

    I have a class that has public variables. After creating a mock of the class, how can I set the public variables? I guess in a similar way to setReturnValue();

    Thanks,

  2. #2
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    May as well ask a second question in this thread too:

    How can I call private methods using mock objects? I get undefined method errors (obviously, they're private methods).

  3. #3
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Private methods are private and not supposed to be tested; the behaviour of a class is observed by using its public interface. What goes on inside doesn't matter.

  4. #4
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    Private methods are private and not supposed to be tested; the behaviour of a class is observed by using its public interface. What goes on inside doesn't matter.
    Hmm. Then how do I test private methods?

  5. #5
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Didn't I just tell you that private methods are not supposed to be testable. If you feel a private method oughta be testable, perhaps it shouldn't be private.

  6. #6
    SitePoint Member
    Join Date
    Jul 2005
    Location
    Watertown, MA
    Posts
    20
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    private methods are indirectly tested via the public methods that use them, provided you haven't partiallyMocked them away.

    Generally speaking, this is what you want -- you know the private method work because the public interface works. If you change the innards, the existing tests should still catch any outwardly visible change of behavoir.

  7. #7
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Perhaps unit testing just isn't as good as I'd like to think it is then. I have some private methods that do some complicated stuff each. The public methods use combinations of these to do the bigger jobs for which the class is intended.

    I want to test that the smaller jobs are getting done correctly. Do you suggest I go back to echoing out variables and stuff again? I'm not actually trying to be obtuse, but I was under the impression unit testing got rid of a lot of that stuff.

  8. #8
    SitePoint Enthusiast Buddha443556's Avatar
    Join Date
    Apr 2004
    Location
    FL, USA
    Posts
    87
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mserms
    Perhaps unit testing just isn't as good as I'd like to think it is then. I have some private methods that do some complicated stuff each. The public methods use combinations of these to do the bigger jobs for which the class is intended.

    I want to test that the smaller jobs are getting done correctly. Do you suggest I go back to echoing out variables and stuff again? I'm not actually trying to be obtuse, but I was under the impression unit testing got rid of a lot of that stuff.
    Sounds like you may have just found a bigger problem which means testing is doing its job. Would it make any sense to put these methods in their own class?

  9. #9
    SitePoint Member
    Join Date
    Jul 2005
    Location
    Watertown, MA
    Posts
    20
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mserms
    Perhaps unit testing just isn't as good as I'd like to think it is then. I have some private methods that do some complicated stuff each. The public methods use combinations of these to do the bigger jobs for which the class is intended.

    I want to test that the smaller jobs are getting done correctly. Do you suggest I go back to echoing out variables and stuff again? I'm not actually trying to be obtuse, but I was under the impression unit testing got rid of a lot of that stuff.
    Yeah I agree with Buddha, if the private methods are that complicated, then I'ld look at doing an "Extract Class" refactoring to pull the out ot a new class that the existing class uses.

    I'm not sure if there is any way to mock the public properties -- is there a good reason for them being public? Why not create getters (and setters as required), moving the public parameters to private and the setting the return value for the getters, etc

  10. #10
    SitePoint Guru BerislavLopac's Avatar
    Join Date
    Sep 2004
    Location
    Zagreb, Croatia
    Posts
    830
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mserms
    I want to test that the smaller jobs are getting done correctly.
    No, you don't. You wan't to test that when someone (another class) calls your classes' public methods, they behave correctly. Your tests couldn't care less about the private methods -- but if they don't work correctly, neither your public methods will, which.

    In other words, always implement to the interface: first determine the public methods for a class, and then implement them. It's alright if you move some of the code into helper private methods, but they are just Toby Zieglers to your president Bartlets.

  11. #11
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mserms
    Perhaps unit testing just isn't as good as I'd like to think it is then. I have some private methods that do some complicated stuff each. The public methods use combinations of these to do the bigger jobs for which the class is intended.

    I want to test that the smaller jobs are getting done correctly. Do you suggest I go back to echoing out variables and stuff again? I'm not actually trying to be obtuse, but I was under the impression unit testing got rid of a lot of that stuff.
    Failure messages will often tell you what you need to know but you do need the odd $this->dump or print_r when something isn't working in a test case. Because tests are quite focussed, it's nothing like as bad as wading through entire scripts and because tests are repeatable at the click of a button, once you've got the test passing you'll never have to do it again.

    Depending on just how complicated this stuff is, you might have found some different responsibilities which could be refactored into classes of their own (as has been mentioned). I find testing is a good influence on the code in various ways - not least that smaller more tightly focussed classes are easier to test and so that's what you tend to write. It could be that this is part of the problem you're having.

    The point about mocks is that they're a design tool. When you define a mock object, you don't need to consider how it will be implemented. All you want to do is to describe how it should interact with the primary class: what methods are called, with what arguments, and what values are returned. The mock objects left behind by the primary class's test are the next step in the design - some pencil sketches to be coloured in with a concrete implementation. Are you trying to test the mock objects too soon? Wait until you come to write implementations for these.

    Incidentally, wouldn't it be nice if there was some way to code generate tests for mock objects based on the expectations set in other test cases...

  12. #12
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by McGruff
    Incidentally, wouldn't it be nice if there was some way to code generate tests for mock objects based on the expectations set in other test cases...
    Is that a formal request? You are the second person to ask for this...

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  13. #13
    SitePoint Member
    Join Date
    Jul 2005
    Location
    Watertown, MA
    Posts
    20
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Hi...



    Is that a formal request? You are the second person to ask for this...

    yours, Marcus
    Well even if McGruff doesn't second it, "Yes please! "

  14. #14
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by NielsenE
    Well even if McGruff doesn't second it, "Yes please! "
    I have been wanting to look at this for some time, but I have been so busy with the web browser portion that now is really the first chance I have had to refactor the mock objects. Once the internals have been sorted. I can evaluate the options.

    I'd realy like to have a method of syncing the mocks with their undelying objects.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  15. #15
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Nielsen, unfortunately that's the impression I got

    In this particular case, testing the public method requires setting up a silly number of mocks and so forth, when really it's the private methods that are more prone to error. Ah well...

    Does anyone know about setting the public variables of a mock?

  16. #16
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mserms
    Does anyone know about setting the public variables of a mock?
    IIRC, when this has come up in the past:

    PHP Code:
    $mockSomething->var 'abc'
    works.
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  17. #17
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    IIRC, when this has come up in the past:

    PHP Code:
    $mockSomething->var 'abc'
    works.
    I remember asking the original question and being perplexed about the answer. But then I realized how primitive PHP still is. You can freely set and get any variable that hasn't been declared. This works:
    PHP Code:
    class Foo {
        private 
    $bar;
    }

    $foo = new Foo;
    $foo->baz 42;
    echo 
    $foo->baz."\n"

    But this fails:

    PHP Code:
    $foo->bar 43
    I guess the only way to control all instance variable accesses is to use __get() and __set().
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  18. #18
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This also works:

    PHP Code:
    class Foo {
        private 
    $bar;
    }

    Mock::Generate('Foo');

    class  
    FooTest extends UnitTestCase {

        function 
    testMockFoo() {
            
    $mock = new MockFoo($this);
            
    $mock->baz 42;
            
    $mock->bar 43;
        }

    Which is not surprising. There is no reason why the mock generation process should clone the variable declarations.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  19. #19
    SitePoint Addict mserms's Avatar
    Join Date
    Jun 2001
    Location
    Scotland
    Posts
    230
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You guys may be right about the complexity of this class, I'll have a think about that.

    The reason to make them public is to avoid writing getters and setters. I guess they're (getters and setters) one of those never ending debates though.

    If I really need to, I'll rewrite my class to use getters just so that I can unit test. Although, I'd rather not.

    Thanks for the help with this everyone - things are becoming clearer.

  20. #20
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by mserms
    You guys may be right about the complexity of this class, I'll have a think about that.
    You are about to hit a classic chicken and egg situation. You want unit tests to safely refactor the class, but the class can't be tested until it's refactored .

    The way out of this trap is to do a single integration test, or a heavily mocked unit test, that covers a lot of code. That way at least you know when it breaks. You won't know where, you don't yet have the fine grain testing, but at least it gives you a safety net to refactor.

    Regarding member variables and private methods, there is not much I can do. However, one of the positive effects of mock objects is that they help you design the code. If it's hard to test then it's probably inflexible in other ways.

    yours, Marcus

    p.s. McGruff's forum now has a unit testing section.
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  21. #21
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    If it's hard to test then it's probably inflexible in other ways.
    Detestable (adjective): software that isn't testable.

    Love that quote.

  22. #22
    SitePoint Evangelist jplush76's Avatar
    Join Date
    Nov 2003
    Location
    Los Angeles, CA
    Posts
    460
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Hi...
    You are about to hit a classic chicken and egg situation. You want unit tests to safely refactor the class, but the class can't be tested until it's refactored .
    *sniffles
    this is sadly where I'm at now trying to maintain a mess of code that I inherited. I'm going to attempt to at least get all the functionality under a webtest case so I can start refactoring into more testible code (p.s. thanks for adding that lovely feature).
    My-Bic - Easiest AJAX/PHP Framework Around
    Now Debug PHP scripts with Firebug!

  23. #23
    SitePoint Member
    Join Date
    Jul 2005
    Location
    Watertown, MA
    Posts
    20
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    "Pointless" getter/setters have long been one of my chief complaints of OOP; however now that I'm doing TDD; I'm finding that I seldom need them. When I do its appropriate and I don't mind writing them.

  24. #24
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just dreaming out loud - I'd hate to add to your workload. If I made a request I'd want to try to offer a possible solution at the same time.

  25. #25
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Off Topic:

    p.s. McGruff's forum now has a unit testing section.


    What forum? First I've heard of it...


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •