How to Mock to Spec a unit

57 views
Skip to first unread message

Alwin Mark

unread,
Jan 3, 2014, 8:02:14 AM1/3/14
to phpsp...@googlegroups.com
Hi,

in Ruby I normally have some DAOs and above Model/Service/Controller - Classes which are defining an  Interface on available actions implementing business logic.
Normally when I spec this, I Spec the DAOs itself using sqlite. When I'm specing classes above I mock every depending Class and, so I don't need access the database and prepare fixtures.
In Ruby and Rspec this is a breeze without the usage of dependency injection in the implementation.
Now I have to work with PHP and I would like to do the same, because it worked well for me, but as far as I can see, I have to use dependency injection for every dependency I want to Mock.

Is that correct?

Lets say, I have a GeoInformation Provider Library, returning the region for a given country and zipcode.


http://pastebin.com/MHdG6eiJ
<?php

namespace spec\My\Geo;

use PhpSpec\ObjectBehavior;
use My\Geo\RedBean\R;

class GeoDaoSpec extends ObjectBehavior
{

    public static $dbFile = '/tmp/geoDataTest.data';
 
    function let()
    {
        touch(self::$dbFile);

        $dsn = 'sqlite:' . self::$dbFile;
        $user = null;
        $password = null;

        R::setup($dsn, $user, $password);
    }

    function letgo()
    {
        self::clean();
    }

    function it_is_initializeable()
    {
        $this->shouldHaveType('My\Geo\GeoDao');
    }

    function it_returns_correct_tableName()
    {
        $this->tableName()->shouldEqual("geo");
    }

    function it_saves_an_entry() {
        $this->country = 'IT';
        $this->zipCode= '00178';
        $this->province = 'Roma';

        $this->save()->shouldEqual(1);
    }

    function it_saves_one_more_item_using_the_constructor() {
        $this->beConstructedWith('DE', '79591', 'Baden-Württemberg');
        $this->save()->shouldEqual(1);
    }

    function it_find_geo_entry_by_country_and_zipCode()
    {
        $this->beConstructedWith('DE', '79591', 'Baden-Württemberg');
        $this->save();

        self::getRegionByCountryAndZipcode('DE', '79591')
            ->shouldEqual('Baden-Württemberg');
    }

    function it_lists_all_regions_for_a_country()
    {
        for($i = 0; $i<5; $i++) {
            $entry = new \My\Geo\GeoDao('DE', "1234$i", "Province $i");
            $entry->save();
        }

        $entry = new \My\Geo\GeoDao('UK', "1234$i", "Not Searched");
        $entry->save();

        self::listProvincesForCountry('DE')->shouldHaveCount(5);
    }

}

Now I want to have a GeoProvider Class specking following behaviours:

http://pastebin.com/99Z5FMzN
<?php

namespace spec\My\Geo;

use PhpSpec\ObjectBehavior;

class GeoProviderSpec extends ObjectBehavior
{

    function it_returns_region_for_a_given_country_and_zipCode()
    {
        $this::getRegion('IT', '00189')->shouldReturn('Roma');
    }

    function it_returns_all_regions_for_a_given_country()
    {
    }

    function it_validates_a_country_zipCode_region_tuple()
    {
    }

}

No I would like to mock my GeoDao, because it's already specked with sth. like:

    function it_returns_region_for_a_given_country_and_zipCode(GeoDao $geoDao)
    {
        $geoDao->getRegionByCountryAndZipcode('IT', '00189')->willReturn('Roma');
        $this::getRegion('IT', '00189')->shouldReturn('Roma');
    }

Even this example is very easy, there will be much more complexity in this abstraction Layer.


So what would you suggest? Inject the Dependency to the Dao in the constructor? Use the sqlite DB here as well? Or is there another opportunity?

Greets
Alwin Mark
Reply all
Reply to author
Forward
0 new messages