Page 1 of 1

I need to Mock the result of *two* interfaces on one mock??

Posted: Sat Feb 02, 2008 5:38 pm
by Chris Corbyn
I've got an interface for Header, and I've got an interface for MimeFieldObserver.

I need to test he behaviour of a Header, which implements this Obersver interface since I'll actually need this. Might be one for Pádraic to think about for PHPMock?

Maybe it's a bad design choice, I dunno, but I effectively need my mock generated thus:

Code: Select all

class MyMock implements Header, MimeFieldObserver {
  ... stuff ...
}
Any clues? I can test the two separately, but behaviourally I'd like Headers to be inspected to see if they observe what they belong to. It's partly an implementation detail, but basically because there are multiple types of Header which all take slightly different values I don't want the MimeEntity (e.g. an email message) to know how to write to the concrete implementations, I want the concrete implementations to update when they see a need to (e.g. a new Content-Type being set on the message).

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Sun Feb 03, 2008 6:37 pm
by Jenk
Two mock objects :)

Code: Select all

$mockHeader = new MockHeader($this);
$mockMime = new MockMime($this);
 
$mockHeader->expect("functionThatReturnsMime");
$mockHeader->return("functionThatReturnsMime", $mockMime);

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 3:15 am
by Chris Corbyn
Thanks :) I still can't make sense of what you're trying to demonstrate but I may have been misleading with my question. Effectively I have a situation like this:

Code: Select all

class Message {
  public function setHeaders($headers) { //array of type Header[]
  }
  public function registerFieldChangeObserver(FieldChangeObserver $observer) {
  }
}
What I wanted was to be able to put logic in setHeaders() which checks if each instance in the array implements FieldChangeObserver too, and if so, register it internally.

Code: Select all

 
  public function setHeaders($headers) { //array of type Header[]
    foreach ($headers as $header) {
      if ($header instanceof FieldChangeObserver) {
        $this->registerFieldChangeObserver($header);
      }
    }
    $this->_headers = $headers;
  }
 
However, I can't physically mock that because if I mock the Header interface, although I can set the headers, it won't register it as an observer. And the same for vice-versa.

I ended up just mocking both interfaces as two objects and passing one to setHeaders() and the other to registerFieldChangeObserver() but the result isn't quite the same... mostly down to implementation details though.

Looking at it, it does feel a bit wrong to be automating this observer registration and perhaps it should be done with a factory.

Trying to write a system 100% focused on DI is a fun experience :)

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 5:42 am
by Jenk
So if I understand correctly, you need to verify that the $headers array/object will be "notified"? Or to be more specific, that the object under test will notify the $headers, if it is implementing the FieldChangeObserver interface, and will not if it isn't?

In that case, again two mock objects - one with the implements and one without, then call whatever function it is on the Message object that would kick off the "notify" method.

So something like:

Code: Select all

$mockInterface = new MockFieldChangeObserverObject($this);
$mockNonInterface = new MockNonFieldChangeObserverObject($this);
$mockInterface->expectOnce("notify");
$headers->setHeaders(array($mockInterface, $mockNonInterface));
$headers->notifyObservers();

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 6:50 am
by Chris Corbyn
Are you suggesting a mock concrete classes here? :) I'm kinda opposed to that unfortunately. These days I only mock interfaces... in order to encourage looser coupling. I could write empty classes, but... meh, I don't like it. Maybe the fact jMock refuses to mock classes has convinced me that mocking classes is a bad practise.

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 10:14 am
by Jenk
You're reading too literally into my answers :)

Just get two mocks, one that implements the interface required for headers, and that returns a separate mock that implements the observer interface.

P.S. Mocking interfaces still incurs instantiating a mock object - you can't create an object from interfaces alone :)

Code: Select all

interface SomeInterface {
  public foo ($obj);
}
Mock::generate('SomeInterface', 'MockSomeInterface'); //this eval()'s a class definition for MockSomeInterface
$mock = new MockSomeInterface($this);

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 10:58 am
by Maugrim_The_Reaper
What he said...;).

In PHPMock, mocking an interface still produces an instantiable Mock Class based on the interface. I haven't added a use case for two or more interfaces, presumably because it's a more complicated procedure to mock that - not that it's difficult using Reflection...

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 04, 2008 2:00 pm
by Chris Corbyn
Ah, gotcha :) Yeah, I guess I could drop my type-checking for "Header" in setHeaders() so that an observer which doesn't implement Header can be passed in for the sake of testing :)

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 25, 2008 6:31 pm
by lastcraft
Hi...

Could you not just do this...?

Code: Select all

 
class JustForMocking extends Observable implements SomethingElse { }
Mock::generate('JustForMocking', 'MockObserverAndSomething');
...
$mock = new MockObserverAndSomething();
 
I've assumed SimpleTest here, but I guess the same trick should work in PHPUnit.

To correct a small detail mentioned earlier, you can mock an interface...

Code: Select all

 
interface Stuff { ... }
Mock::generate('Stuff');
...
$stuff = new MockStuff();
 
yours, Marcus

Re: I need to Mock the result of *two* interfaces on one mock??

Posted: Mon Feb 25, 2008 9:21 pm
by Chris Corbyn
Your solution would be more suitable marcus I agree. I guess I was trying to avoid declaring additional classes inside my test file; but that's a bit of a non-issue when all that's declared is a skeleton.