Testing Date And Time with Clock Objects

Did you ever write unit tests for code that dealt with date and time? Since time itself is out of your control, you might have used one of these approaches:

  • Test doubles, e.g. for the DateTime class in PHP. To make this work, DateTime or a factory thereof must be passed to the subject under test via dependency injection. My most popular blog post of all time is still “How to mock time() in PHPUnit” about mocking core functions like date() and time() if necessary (a hacky workaround, mind you)
  • Use derived values of the current time in fixtures and assertions, probably with some margin, e.g.
    assertEquals(\strtotime(“+1 day”), $cache->expiresAt(), “1”)
    where $cache->expiresAt() is the value we test and “1” is the allowed margin.

The latter is not very stable; it is likely that you run into edge cases where the tests are not deterministic. The former does not have this problem, but can result in a complicated setup of the test double.

Luckily, there is a third way, namely using a custom Clock (or Calendar) object that provides the current time and can easily be replaced with an (also custom) test double.

Continue reading on integer-net.com

TDD Kata 01 – The Bowling Game

One of my goals for 2017 is to make TDD katas a part of my daily routine. What is a Kata? Just as in martial arts it is training through repetition, practicing the same exercise again and again until you can do it in your sleep.

Some would say, it is the only way to learn TDD. This makes sense for several reasons: you start in a small, protected scope and can apply pure test driven development. This way you are able to train the different mindset (the red-green-refactor cycle) without frustration. It means, you will not have to learn working around the quirks of a framework at the same time.
Continue reading “TDD Kata 01 – The Bowling Game”

What to mock in a Magento 2 unit test

You write unit tests for a Magento 2 module and need to mock a core class, like the store model. This class has a few dependencies which have more dependencies and it’s getting complicated to mock. Although PHPUnit 5.4 has a createMock() method that automatically stubs methods and let them return new stubs if they have a return type.

Or: you mock a service contract like getList() in the product repository, which takes a search criteria instance as parameter, which must be returned by a search criteria factory. Then it returns a product search result, which has a getItems() method, which returns a array of products. So you end up mocking countless dependendencies for a single method call

Do these situations sound familiar? It does not need to be like that, though! Let me show you a sane way to deal with Magento dependencies.

Continue reading “What to mock in a Magento 2 unit test”

The week on StackExchange #23 / 2016

Shortly before the 5th MageStackDay, here are some questions and answers on magento.stackexchange.com from last week that might interest you:

Magento 2

  • Without answer yet, and probably there is no solution as of Magento 2.0: Localized frontend value for getCustomAttribute() (select or multiselect attributes) – but as I commented: I’m going to continue to ask these questions when I’m hitting walls, and if it’s just to highlight, where the API is incomplete, especially when it’s about the catalog
  • Marius asked a good question on Unit testing source models. Besides my answer on this concrete case, the elaboration by Vinai on “Should I test X?” or “How should I test X?” is a valuable advice for everybody.

Magento 1

EcomDev PHPUnit Tip #13

For years, the test framework EcomDev_PHPUnit is quasi-standard for Magento unit tests. The current version is 0.3.7 and last state of official documentation is version 0.2.0 – since then, much has changed which you have to search yourself in code and GitHub issues. This series shall collect practical usage tips.

Tip #13: Speed up EAV fixtures

If you use the EAV fixtures to create products, categories and customers for tests, the fixture processor or EcomDev_PHPUnit makes a backup of the according tables before each test and restores it afterwards. Since the “magento_unit_tests” test database is copied from the current Magento database by default, this can result in much unnecessary overhead.

We can speed up tests that run several minutes many times over, by cleaning up the EAV tables in the test database. To do so, delete all rows in the entity main tables of the test DB, the associated attributes etc. are deleted automatically with triggers. With one exception: Do not delete the default root category:

delete from catalog_product_entity;
delete from catalog_category_entity where entity_id > 2;
delete from customer_entity;

EcomDev PHPUnit Tip #12

For years, the test framework EcomDev_PHPUnit is quasi-standard for Magento unit tests. The current version is 0.3.7 and last state of official documentation is version 0.2.0 – since then, much has changed which you have to search yourself in code and GitHub issues. This series shall collect practical usage tips.

Tip #12: Cache

You can turn caches on and off per test, using the following annotations:

/**
 * @test
 * @cache on all
 */
public function testWithCache()

/**
 * @test
 * @cache off all
 */
public function testWithoutCache()

/**
 * @test
 * @cache off all
 * @cache on layout
 * @cache on block_html
 */
public function testWithSomeCachesTurnedOn()


/**
 * @test
 * @cache on all
 * @cache off translate
 * @cache off config
 */
public function testWithSomeCachesTurnedOff()

The annotations are executed in order, so if you use “all”, it should always come before all other @cache annotations.

EcomDev PHPUnit Tip #11

For years, the test framework EcomDev_PHPUnit is quasi-standard for Magento unit tests. The current version is 0.3.7 and last state of official documentation is version 0.2.0 – since then, much has changed which you have to search yourself in code and GitHub issues. This series shall collect practical usage tips.

Tip #11: Minimal Fixtures For Product Types

Below are some example fixtures for different product types. They are as minimal as possible to create products and their relationships. In most cases you will want to add more attributes like name, visibility, status, price and stock status.

Continue reading “EcomDev PHPUnit Tip #11”