Page 2 of 2

Re: DataMapper and TableDataGateway Design Concepts

Posted: Sat Dec 13, 2008 7:24 pm
by allspiritseve
jshpro2 wrote:"should", I'm just telling you the problem I personally ran into. Just because it should be designed one way doesn't mean simpletest choose to design it that way. I understand how it "should" work, all I was saying is I personally found it to be a pain to make it work that way.
I'm just trying to explain a possible solution to your problem. I don't think it has anything to do with the way SimpleTest is designed. My "should" earlier was not referring to what SimpleTest should do, but what you should do.
jshpro2 wrote:Flexibility comes inversely to control. If you don't program directly in machine code you're severely handicapping your programming capabilities too ;-)
I'm not sure how that applies, but we're not programming here, we're testing. When you test, you want to control every outside element, which includes not only what uses the code under test, but what the code uses. If you're not mocking you're only testing one side of your code.

Re: DataMapper and TableDataGateway Design Concepts

Posted: Sun Dec 14, 2008 4:20 am
by josh
allspiritseve wrote:I'm just trying to explain a possible solution to your problem. I don't think it has anything to do with the way SimpleTest is designed. My "should" earlier was not referring to what SimpleTest should do, but what you should do.
I understand, I'm just saying I sunk several hours into it and didn't get anywhere. Just like this dialogue :lol: Feel free to show me up though, you seem to be more motivated then me, if you do it I'd love to have the code shared with me
jshpro2 wrote:I'm not sure how that applies, but we're not programming here, we're testing. When you test, you want to control every outside element, which includes not only what uses the code under test, but what the code uses. If you're not mocking you're only testing one side of your code.
Tests are a program. Actually you should drive to eliminate duplication between tests and implementation, but everyone has different goals. I'm not saying there's no use for mocks, I'm just saying I realized I didn't need them.. and if I ever do I doubt I'll need overloading. The amount of typing it takes to make getters and setters is nominal compared to the amount of typing doing OOP + TDD saves compared to not doing OOP + TDD, I have found. Plus with overloading you have no explicit interface. I like to use abstract classes in place of interfaces, etc... Everyone has a different programming style.

IMO mocking is just 1 step closer to reading in the source file and actually asserting the contents of the class itself, instead of doing what TDD is supposed to do which is test the black box, outward facing API / functionality. Maybe you can convince me otherwise, what can I do with a mock I can't do with a stub? With mocks I can make sure my setters get called, with stubs you can test that same behavior by calling the setter(s) and then asserting the getters return the correct values.

Re: DataMapper and TableDataGateway Design Concepts

Posted: Sun Dec 14, 2008 10:37 am
by allspiritseve
jshpro2 wrote:Feel free to show me up though, you seem to be more motivated then me, if you do it I'd love to have the code shared with me
Proof of concept, if you will...

Code: Select all

include ('MyClass.php');
 
class ExplicitInterface extends OverloadedClass {
 
function nonExistentMethod()    {
}
 
}
 
Mock::Generate ('ExplicitInterface', 'MockOverloadedClass');
 
class TestMyClass extends UnitTestCase  {
 
function __construct() {
    $this->UnitTestCase();
}
 
function setUp()    {
    $this->mock = new MockOverloadedClass();
    $this->class = new MyClass ($this->mock);
}
 
function testNonExistentMethod()    {
    $this->mock->expectOnce ('nonExistentMethod', array ('1'));
    $this->class->poke();
}
 
}
jshpro2 wrote:I doubt I'll need overloading....with overloading you have no explicit interface.
Agreed, I've found my code gets a lot more explicit when I steer away from overloading. There are situations where it comes in handy though, like the lazy loading code I mentioned earlier.
jshpro2 wrote:IMO mocking is just 1 step closer to reading in the source file and actually asserting the contents of the class itself, instead of doing what TDD is supposed to do which is test the black box, outward facing API / functionality. Maybe you can convince me otherwise, what can I do with a mock I can't do with a stub? With mocks I can make sure my setters get called, with stubs you can test that same behavior by calling the setter(s) and then asserting the getters return the correct values.
My understanding of a stub is a class that doesn't actually do anything. You just mock it and set return values. A mock, on the other hand, can set expectations for what is passed to it. You sound like you're using a fleshed-out class that actually has behavior (ie neither a mock or a stub).

If the classes the class under test uses are implemented, then you're testing both classes at once. How do you know, if the class under test returns the wrong value, whether the fault lies in the class under test or the supporting class? However, if you mocked that supporting class, told it to expect certain methods to be called, and to return certain values, then you are in control of that class. If everything but the class under test is controlled, you know that the only source for error is the class under test.

Additionally, with TDD, you can mock out classes you haven't built yet. Not only does this allow you to test a class that you otherwise couldn't, because it has too many dependencies, but you are also giving that mock object an interface that can be later used for when you're testing THAT class later on down the road. Hence why all the TDD documentation talks about the design of your application flowing out from that first test. Mocking helps you design your application just as much as it helps you test it.

I'm stepping off my soapbox now. :D

If you'd like to discuss this further, maybe we should start a thread in the TDD forums and not pollute this thread any longer?

Re: DataMapper and TableDataGateway Design Concepts

Posted: Sun Dec 14, 2008 12:16 pm
by josh
allspiritseve wrote:Proof of concept, if you will...
That tests the explicit method, I beleive the problem I encountered was telling it to expect the explict Method and having the mock notice that _call correlates to the expectOnce. Im sure its possible it was just a pain
jshpro2 wrote:My understanding of a stub is a class that doesn't actually do anything. You just mock it and set return values.
Stubs can be anything from hard coded returns to a psuedo implementation as far as I know..

jshpro2 wrote: How do you know, if the class under test returns the wrong value, whether the fault lies in the class under test or the supporting class?However, if you mocked that supporting class, told it to expect certain methods to be called, and to return certain values, then you are in control of that class.
Because multiple tests break since each class has tests. Then you use common sense to find the problem
jshpro2 wrote:Not only does this allow you to test a class that you otherwise couldn't, because it has too many dependencies, but you are also giving that mock object an interface that can be later used for when you're testing THAT class later on down the road.
Stubs do the same things as mocks in that regard.
maybe we should start a thread in the TDD forums and not pollute this thread any longer?
I'm fine, feel free to start it and I'll contribute :wink:

I realize mocks give you a better harness, like I said you can either have high control and low flexibility ( brittle tests), or you can have less control and more flexibility ( ability to refactor implementation without setting off tests ). If my tests go off every time I change a class' implementation, whats the point of the tests? They'd just be red 99.9% of the time I was refactoring. When I refactor I work in small tests and stop if I get red.

Re: Are mocks necessary?

Posted: Fri Dec 26, 2008 5:13 pm
by Chris Corbyn
Just want to chime in here and say how Yay Mock currently handles this. It tests the interface so it knows that __call() invocations need to be massaged to reflect the method the user invoked. This is uncommitted code though - I've got a bunch of stuff I need to commit. Usually you'd have wrappers in your base test case to deal with the context creation and assertion.

Code: Select all

<?php
 
require_once 'test-suite/lib/simpletest/unit_tester.php';
require_once 'test-suite/lib/simpletest/autorun.php';
require_once 'test-suite/lib/yaymock/yay_mock.php';
require_once 'test-suite/lib/yaymock/yay_convenience.php';
 
class SutWithCall {
  public function __call($method, $args = array()) {
  }
}
 
class TestCallOverloadedMock extends UnitTestCase {
 
  public function testMockedInterfaceWithCallMatchesTypeHint() {
    $context = new Mockery();
    $mockSut = $context->mock('SutWithCall');
    $this->assertIsA($mockSut, 'SutWithCall');
  }
 
  public function testMockedInterfaceAllowsOverloadedMethodCall() {
    $context = new Mockery();
    $mockSut = $context->mock('SutWithCall');
    $context->checking(Expectations::create()
      -> one($mockSut)->fakeMethod(42)
    );
    $mockSut->fakeMethod(42);
    $context->assertIsSatisfied();
  }
  
  public function testMockObjectCanRunActionsFromOverloadedMethod() {
    $context = new Mockery();
    $mockSut = $context->mock('SutWithCall');
    $context->checking(Expectations::create()
      -> one($mockSut)->fakeMethod(42) -> returns(7)
    );
    $this->assertEqual(7, $mockSut->fakeMethod(42));
    $context->assertIsSatisfied();
  }
 
}

Code: Select all

chrisbook:swiftmailer_v4 chris$ php -v
PHP 5.2.6 (cli) (built: Sep 14 2008 08:23:59) 
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
 
chrisbook:swiftmailer_v4 chris$ php TestCallOverloadedMock.php 
TestCallOverloadedMock.php
OK
Test cases run: 1/1, Passes: 2, Failures: 0, Exceptions: 0
chrisbook:swiftmailer_v4 chris$