5.3. Exposing

5.3.1. Methods

Exposing a method will simply make its visibility public this does not interfere with any actions behavior of the method:

class MyClass
{
    protected function foo()
    {
        return 'bar';
    }
}
$mock = $this->niceMock('MyClass')
             ->expose('foo')
             ->get();
$mock->foo();

If you need to expose several methods there is also a variety of ways this can be done:

$mock = $this->niceMock('MyClass')
             ->expose('foo')
             ->expose('bar')
             ->get();
$mock = $this->niceMock('MyClass')
             ->expose(['foo', 'bar'])
             ->get();
$mock = $this->niceMock('MyClass')
             ->expose('foo', 'bar')
             ->get();

Some caveats:

  • The method you are exposing must exist, but it doesn’t have to be protected. Exposing a public method is allowed but would have no effect.
  • You cannot expose a private method. If you try you will get an exception.

5.3.2. All Methods

In some cases you may want to expose all the non-public methods in a mock. This is generally unwise because your testing code should ideally only use the public API provided by the objects and services that you are testing.

$mock = $this->niceMock('MyClass')
             ->exposeAll()
             ->get();

$mock->secretMethod();

exposeAll() will actually retrieve the methods available on the object and promote any method that is not final or private to a public visibility. See Mocking Final Classes and Methods for more information.

5.3.3. Properties

In some case you may also want to get or set properties on an object that do not have a public visibility.

class MyClass
{
    protected $value = 'foo';
}
public function testValueIsFoo()
{
    $myClass = new MyClass();
    $this->assert($this->getProperty($myClass, 'value'))->equals('foo');
}

The above will work for all visibilities of a property.

Likewise you can use the setProperty method provided by Concise\Core\TestCase:

public function testValueIsBar()
{
    $myClass = new MyClass();
    $this->setProperty($myClass, 'value', 'bar');
    $this->assert($this->getProperty($myClass, 'value'))->equals('bar');
}

private properties are attached to a specific class. Therefore a parent and child class can contain private instance variables by the same name that are completely independent.

class A
{
    private $value = 'foo';
}

class B extends A
{
    private $value = 'bar';
}
public function testPrivates()
{
    $object = new B();
    $parent = get_parent_class($object);

    $this->getProperty($object, 'value');                 // 'bar'
    $this->getProperty($object, 'value', $parent);        // 'foo'

    $this->setProperty($object, 'value', 'baz');          // B::$value is set.
    $this->setProperty($object, 'value', 'baz', $parent); // A::$value is set.
}

Concise will automatically determine which class in the hierarchy contains the property to be set if no explicit class name is provided. If multiple classes contain the same property the most child class is used.

When an explicit class is provided that class is always used whether the property exists on that class or not.