Building tests for test-driven development
Edit on GitHubThis document helps you understand the main concepts of testing with Spryker and see how simple it is to build tests. You will use the test-driven development (TDD) approach.
Spryker’s testing structure and data handling make it very easy to develop using TDD. You will build a simple module that reverses a string and test it.
Using TDD, you will write the test first, see it fail, and then write the string reverser that makes the test pass.
1. Build the test that fails
As everything in Spryker is modular, tests are also modular. To build a new test, you simply add a new module inside your tests.
Spryker introduces a new namespace for testing in your project called PyzTest
.
As you are going to work with Zed, the test module is for Zed:
- Create a new test module inside the tests directory in you project
tests/PyzTest/Zed
and call itStringReverser
. - Spryker uses
Codeception
as a testing framework. Intests/PyzTest/Zed/StringReverser
, usingCodeception
, add the config file for your new module and call itcodeception.yml
. The config looks like this:
namespace: PyzTest\Zed\StringReverser
paths:
tests: .
data: _data
support: _support
output: _output
coverage:
enabled: true
remote: false
whitelist: { include: ['../../../../src/*'] }
suites:
Business:
path: Business
actor: StringReverserBusinessTester
modules:
enabled:
- Asserts
- \PyzTest\Shared\Testify\Helper\Environment
- \SprykerTest\Shared\Testify\Helper\LocatorHelper:
projectNamespaces: ['Pyz']
- Add modules
Config
andDependencyProvider
:
namespace Pyz\Zed\StringReverser;
use Spryker\Zed\Kernel\AbstractBundleConfig;
class StringReverserConfig extends AbstractBundleConfig
{
}
namespace Pyz\Zed\StringReverser;
use Spryker\Zed\Kernel\AbstractBundleDependencyProvider;
class StringReverserDependencyProvider extends AbstractBundleDependencyProvider
{
}
- Add the
Business
folder insidetests/PyzTest/Zed/StringReverser
. - From
Codeception
, generate the needed test classes:
vendor/bin/codecept build -c tests/PyzTest/Zed/StringReverser
- Create a facade test class to add your test inside it. The facade test class looks like this:
Code sample
namespace PyzTest\Zed\StringReverser\Business;
use Codeception\Test\Unit;
/**
* @group PyzTest
* @group Zed
* @group StringReverser
* @group Business
* @group Facade
* @group StringReverserFacadeTest
* Add your own group annotations below this line
*/
class StringReverserFacadeTest extends Unit
{
/**
* @var \PyzTest\Zed\StringReverser\StringReverserBusinessTester
*/
protected $tester;
}
- Spryker can generate transfer objects for testing using a concept called Data Builders*. Data Builders generators work similarly to transfer generators, except that they use data fakers to generate random data for testing purposes. You can generate Data Builders using the same transfer object schemas and running the command
console transfer:databuilder:generate
.
To add the data faker rules for the test, create a data builder schema. Inside tests/
, create a new directory called _data
. Then, add the data builder schema inside the directory and call it string_reverser.databuilder.xml
.
The schema looks very similar to a transfer object schema. This schema only adds the rules when generating the data builders.
You can generate the data builders without the rules and without the schema.
Code sample
<?xml version="1.0"?>
<transfers
xmlns="spryker:transfer-01"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="spryker:transfer-01 http://static.spryker.com/transfer-01.xsd"
>
<transfer name="StringReverser">
<property name="originalString" dataBuilderRule="realText(20, 2)"/>
<property name="reversedString" dataBuilderRule="realText(20, 2)"/>
</transfer>
</transfers>
- Data builders return transfer objects of the same type of the data builder. You need to have a transfer object called
StringReverser
so that the data builder can work.
Data builders cannot even be generated if the transfer object is not there. In src/Pyz/Shared/StringReverser/Transfer
, add the StringReverser
transfer.
Code sample
<?xml version="1.0"?>
<transfers xmlns="spryker:transfer-01"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="spryker:transfer-01 http://static.spryker.com/transfer-01.xsd">
<transfer name="StringReverser">
<property name="originalString" type="string"/>
<property name="reversedString" type="string"/>
</transfer>
</transfers>
- Generate the transfer object first:
console transfer:generate
- Generate the data builder:
console transfer:databuilder:generate
You must have both of them generated.
- Add the test method. Test if the string is reversed correctly.
A test in Spryker consists of three main blocks:
- Arrange—to prepare the test data.
- Act—to act on the data.
In the case described in this tutorial, Act calls the facade method.
- Assert—to check the results.
Code sample
/**
* @return void
*/
public function testStringIsReversedCorrectly(): void
{
// Arrange
$stringReverserTransfer = (new StringReverserBuilder([
'originalString' => 'Hello Spryker!'
]))->build();
// Act
$stringReverserFacade = $this->tester->getLocator()->stringReverser()->facade();
$stringReverserResultTransfer = $stringReverserFacade->reverseString($stringReverserTransfer);
// Assert
$this->assertEquals(
'!rekyrpS olleH',
$stringReverserResultTransfer->getReversedString()
);
}
- Run the test using the command
vendor/bin/codecept run -c tests/PyzTest/Zed/StringReverser
.
The test at this point must fail and give an error that the StringReverserFacade
cannot be resolved because it does not exist.
2. Make the test pass
Write the actual logic (feature) to reverse a string and make the test pass:
- In Zed, add a new module called
StringReverser
. - Add the facade and the needed logic to reverse the string in a model. Your Zed module must have
StringReverserConfig
andStringReverserDependencyProvider
so that the class locator can work with your test.
Use the code generators to generate the module in Zed console code:generate:module:zed StringReverser
.
Code samples
namespace Pyz\Zed\StringReverser\Business;
use Generated\Shared\Transfer\StringReverserTransfer;
use Spryker\Zed\Kernel\Business\AbstractFacade;
/**
* @method \Pyz\Zed\StringReverser\Business\StringReverserBusinessFactory getFactory()
*/
class StringReverserFacade extends AbstractFacade implements StringReverserFacadeInterface
{
/**
* @param \Generated\Shared\Transfer\StringReverserTransfer $stringReverserTransfer
*
* @return \Generated\Shared\Transfer\StringReverserTransfer
*/
public function reverseString(StringReverserTransfer $stringReverserTransfer): StringReverserTransfer
{
return $this->getFactory()
->createStringReverser()
->reverse($stringReverserTransfer);
}
}
namespace Pyz\Zed\StringReverser\Business;
use Pyz\Zed\StringReverser\Business\Reverser\StringReverser;
use Pyz\Zed\StringReverser\Business\Reverser\StringReverserInterface;
use Spryker\Zed\Kernel\Business\AbstractBusinessFactory;
class StringReverserBusinessFactory extends AbstractBusinessFactory
{
/**
* @return \Pyz\Zed\StringReverser\Business\Reverser\StringReverserInterface
*/
public function createStringReverser(): StringReverserInterface
{
return new StringReverser();
}
}
namespace Pyz\Zed\StringReverser\Business\Reverser;
use Generated\Shared\Transfer\StringReverserTransfer;
class StringReverser implements StringReverserInterface
{
/**
* @param \Generated\Shared\Transfer\StringReverserTransfer $stringReverserTransfer
*
* @return \Generated\Shared\Transfer\StringReverserTransfer
*/
public function reverse(StringReverserTransfer $stringReverserTransfer): StringReverserTransfer
{
$reversedString = strrev($stringReverserTransfer->getOriginalString());
$stringReverserTransfer->setReversedString($reversedString);
return $stringReverserTransfer;
}
}
- Run the test again
vendor/bin/codecept run -c tests/PyzTest/Zed/StringReverser
The test must pass.
Thank you!
For submitting the form