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

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
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

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

Post 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).
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

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

Post by Jenk »

Two mock objects :)

Code: Select all

$mockHeader = new MockHeader($this);
$mockMime = new MockMime($this);
 
$mockHeader->expect("functionThatReturnsMime");
$mockHeader->return("functionThatReturnsMime", $mockMime);
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

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

Post 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 :)
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

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

Post 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();
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

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

Post 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.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

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

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

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

Post 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...
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

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

Post 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 :)
lastcraft
Forum Commoner
Posts: 80
Joined: Sat Jul 12, 2003 10:31 pm
Location: London

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

Post 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
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

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

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