3

Is it possible to build object like this (implementing interface and using a trait at the same time) in PHPUnit mock builder?

<?php

class FooClassThatD implements BarInterface
{
    use BazTrait;
}
Mateusz Charytoniuk
  • 1,820
  • 20
  • 31
  • 2
    Have you read in http://sebastian-bergmann.de/archives/906-Testing-Traits.html the following? *"PHPUnit 3.6 [...] supports the testing of traits through the new `getObjectForTrait()` method. This method reuses the mock object code generator and returns an object of a class that uses the trait-under-test."* - That was back in January 2011. So what did you try, because it makes me assume the answer is *Yes* and I wonder if that was already it. – hakre Oct 15 '12 at 08:15
  • I want to achive anything that will allow this test to pass: `$foo = $this->getMockForTrait('BazTrait')->...; $this->assertInstanceOf('BarInterface', $foo);` – Mateusz Charytoniuk Oct 15 '12 at 11:38
  • You do not need to test that, PHP itself covers this at compile time. You are only looking for concrete types here, so I wonder why one should even need to test that. In case that's not the case, create such an object at runtime, I've outlined this here: [How to generate or modify a PHP class at runtime?](http://stackoverflow.com/q/12651179/367456) - however as written, it is pretty useless because you specify the interface literally and then testing for it. (Edited, wrong link) – hakre Oct 15 '12 at 11:53
  • 1
    @hakre - I suspect Mateusz needs the mock to both a) use a trait and b) implement an interface at the same time so that it can be used as a dependency that expects the known interface. I doubt the test consists solely of testing for the interface. – David Harkness Oct 15 '12 at 17:47
  • @DavidHarkness: The question I linked contains a builder for these combinations, it does all this but does not create the mock. Looks like this could be combined with your answer well, it's just generating code at runtime and running it with eval (comparable to the Mock lib). Do you think it's worth to suggest this as a new feature for Phpunit (create Mock object with trait+interface dynamically)? – hakre Oct 15 '12 at 18:31
  • @hakre - Yes, I could see adding `MockBuilder::addTrait` that would allow you to build a mock with one or more traits. Whether or not Sebastian will like it though is anyone's guess. ;) – David Harkness Oct 15 '12 at 18:44
  • Well if MateuszCharytoniuk would chime in and explain in simple words for what this is needed, I'm sure if the scenario is worthy, why would Sebastian not want that? Good ideas start somewhere, let's see if there's some real need behind that so to ensure this ain't any bloat. So feedback welcome and probably some counter-arguments against my earlier questioning are needed :) . – hakre Oct 15 '12 at 21:29
  • I want to test an object container which `extends SplObjectStorage` and only accepts objects with `BarInterface`. `BazTrait` is a default implementation of `BarInterface`. If mocking that (object impelmenting interface and using trait at the same time) would be possible, I would be able to mock my object container behaviour precisely. – Mateusz Charytoniuk Oct 16 '12 at 06:30

1 Answers1

4

I don't think this is possible with the native mock object methods because they use a specific template to mock a class with a trait that doesn't allow any extension points. You can get around it easily with a test-specific class from which you build your mock.

abstract class BarWithBazTraitTestClass implements BarInterface
{
    use BazTrait;
}

Create a mock for this class as you would any other abstract class.

$mock = $this->getMockForAbstractClass('BarWithBazTraitTestClass');
David Harkness
  • 35,992
  • 10
  • 112
  • 134