We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

[PHPUnit]Testing Models

How to test model proper way?

I have some code in models I want to test. I found in phalcon incubator there is class ModelTestCase. It setup db connection base on DI.

My default DI set db service as default db with my data. To not lose data I created new DI for test where db service return connection with test database. I found that I need to manually prepare this database, run migrations on this test database (here is first problem), populate db, run tests, delete database.

Is there maybe easier way of testing models?

Problems:

  1. If I run test in the same directory that I develop app .phalcon/migration-version will be in highest point so I need create hack to run migrations on test connection. Of course I can use Travis CI to run test and then everything works fine, but if I write tests I want first run them locally before commiting something to repository.

  2. If I have some Class that use Model::find() method it is nearly impossible to test that code. I don't undestand why using static methods when testing them is so hard.

  3. Is there maybe ready mock Db adapter which simulate db connection but all ORM relations works in the memory?

P.S. Now I'm using phpspec/prophecy to mock almost all ORM functions and testing my code without DB, but again static make this very hard. For example I don't find way to mock Model::create method :(.

For a quick answer, i can say you to use DBUnit (more info on the phpunit doc). It allows you to define unit test with phpunit that initialize/populate your test database following the given set of data. Then it runs the test with your good database.

(you may need to use this "solution" latter with dbunit : https://gist.github.com/SneakyBobito/6168877#file-phpunittestdb-php)

Of course I can use PHPUnit, but for unit testing using DB is overhead. I was hopping to use something like in Doctrine:

$adapter = new Doctrine_Adapter_Mock('mysql'); $connection = Doctrine_Manager::getInstance()->openConnection($adapter);

This way ORM is working but I don't need set DB to work. Everything is in Memory. Fast and easy. If you have a lot of tests which use Database you can wait 30 minutes before travis end testing.

edited Mar '14

It looks like i have misunderstood your needs. Actually you are searching for a solution to run tests faster (without db) with a memory adapter for models (or something that allows to use model without db), right ?

Dont know if phalcon models offer such a tool, but indeed it would be interesting and if it doesnt exist it can be a good NFR.

But one question remains, how do you define your set of data with the doctrine mock adapter ?

For Unit Test I always setup them in tests itself. Sometemise in setUp() sometime in test code.

For example if I have entity Site and Domain. To test simple scenario you use something like this:

$domain = new Domain(); $domain->setName('name' => 'google.com'); $site = new Site(); $site->setDomain($domain); $this->assertEqual($site->getUrl(), 'https://google.com');

Or other test ORM

$domain = new Domain(); $domain->create(array('name' => 'google.com')); $domainRepository = new DomainRepository(); $this->assertSame($domain, $domainRepository->findByName('google.com');

DomainRepository i n this example use Domain::findFirst(array('name = :name:', 'bind' => array('name' => 'google.com')));

Now if I want to test this kind of code I must do some sort of mocking hell to mock Domain::findFirst(). Mocking static methods is not easy.

Sounds exactly like what I need. Did you find any good solution?

edited Mar '14

I changed my approach. Currently I rewrite whole ORM to DataMapper approach. I working on publishing final version on GitHub.

What is done (classes):

  • Manager
  • Repositories
  • Entities with lazy loaded relations
  • Table (as data source - Mapper)
  • Entity Hydrator
  • Collections (for lazy loading)
  • ProxyEntityAbstract (for lazy loading)
  • MySql Adapter

What need to be done:

  • Query object (to write SQL in OO way inside Table objects)
  • Criteria object (to work with no-SQL data stores)
  • Unit of Work to easy saving all relations objects
  • Autogenerating EntityBase, Repositories, ProxyEntities
  • Support other adapters

because of generators it will be connected with command line tool. It's not easy to write additional tasks in phalcon devtools so I decide to use Symfony\Console and bundle it in my Phalcon Starter so first version of DataMapper won't be easy to use outside of my Phalcon Starter.

Hi there!, did you publish it already?

Cheers!



21.7k

Hello. Enybody can solve this problem easily?