4

I am learning Codeception and I wonder when I should use setUp() or tearDown() and when I should use _before() or _after(). I don't see no difference. Both methods are run before or after a single test in my testfile? Thanks,

astridx
  • 6,581
  • 4
  • 17
  • 35
  • What's the point? The methods have exactly the same behavior, just they're from different libraries. – Gabriel Heming Jan 30 '17 at 11:40
  • But why did Codeception integrate this methods? I think there must be a reason for this. Is it so, that it is the same for Unit Test and if I go on with functional test and acceptance test I do need this methods? – astridx Jan 30 '17 at 11:48
  • Oh, that's another question, doesn't the difference, but the purpose/reason. – Gabriel Heming Jan 30 '17 at 11:58
  • Take a look at the link above. Until now, there's no need for a full answer: http://stackoverflow.com/a/13943027/1628790 – Gabriel Heming Jan 30 '17 at 12:01
  • Thank you for your answer. But now I still do not know whether it is advantageous to use the method _before () or to use the method setup() when I create unit tests with codeception. With the sentence "But why did Codeception integrate this methods" I ment not the purpose of the method setup(). I ment the methode _before(). – astridx Jan 30 '17 at 12:23
  • It's the first principle of unit test, every test must be done individually. SetUp/_before ensure that every necessary object or state had to be done before each test (db connection, file creation, object state, etc...). When you have a global state that must be clear (file, connection, object) tearDown/_after ensure that the clean is done. Or, if each method you must log the result, setUp/_before create the connection and tearDown/_after commits the result. Just it, it's a principle. If you don't need, just don't use it... – Gabriel Heming Jan 30 '17 at 12:30

1 Answers1

5

As Gabriel Hemming has mentioned, setUp() and tearDown() are PHPUnit's way of setting up the environment before each test is run and tearing down the environment after each test is run. _before() and _after() is how codeception's way of doing this.

To answer your question, about why codeception has different set of methods for this let me refer you to codeception's documentation: http://codeception.com/docs/05-UnitTests#creating-test

As you see, unlike in PHPUnit, the setUp and tearDown methods are replaced with their aliases: _before, _after.

The actual setUp and tearDown are implemented by the parent class \Codeception\TestCase\Test and set the UnitTester class up to have all the cool actions from Cept-files to be run as a part of your unit tests.

The cool actions the docs are referring to are any modules or helper classes that can now be used in your unit test.

Here is a good example of how to use modules in your unit test: http://codeception.com/docs/05-UnitTests#using-modules

Let's have an example of setting up fixture data in a unit test:

<?php


class UserRepositoryTest extends \Codeception\Test\Unit
{
    /**
     * @var \UnitTester
     */
    protected $tester;

    protected function _before()
    {
        // Note that codeception will delete the record after the test.
        $this->tester->haveInDatabase('users', array('name' => 'miles', 'email' => 'miles@davis.com'));
    }

    protected function _after()
    {

    }

    // tests
    public function testUserAlreadyExists()
    {

        $userRepository = new UserRepository(
            new PDO(
                'mysql:host=localhost;dbname=test;port=3306;charset=utf8',
                'testuser',
                'password'
            )
        );

        $user = new User();
        $user->name = 'another name';
        $user->email = 'miles@davis.com';

        $this->expectException(UserAlreadyExistsException::class);

        $user->save();

    }
}

class User
{
    public $name;
    public $email;

}

class UserRepository
{
    public function __construct(PDO $database)
    {
        $this->db = $database;
    }

    public function save(User $user)
    {
        try {
            $this->db->prepare('INSERT INTO `users` (`name`, `email`) VALUES (:name, :email)')
                ->execute(['name' => $user->name, 'email' => $user->email]);
        } catch (PDOException $e) {
            if ($e->getCode() == 1062) {
                throw new UserAlreadyExistsException();
            } else {
                throw $e;
            }
        }

    }
}
Community
  • 1
  • 1
thomasstuttard
  • 245
  • 2
  • 7
  • Your code example is an integration test, not a unit test. – Daniel W. Aug 16 '21 at 09:03
  • 1
    I would argue it is a unit test, in that it is testing that the repository class saves to the database. Maybe the UserRepository should be renamed to a PdoUserRepository, and then PdoUserRepository should implement a UserRepositoryInterface. Then you could rename the test to be PdoUserRepositoryTest. This, in my opinion, would show that it was a unit test in a better way. Regardless, the question is about codeception’s use of _before and _after methods. I feel my answer, answers that question sufficiently. – thomasstuttard Aug 17 '21 at 13:19
  • 1
    Your answer is fully helpful and sufficient not only to answer the OPs concern but also to people who find this through a search engine. I'm just adding a comment to make things a little more accurate. To turn this integrationtest into a unittest, the classes `PDO` and `PDOException` must be replaced by mocks. "Unit" test means, you are testing a single unit. In the given code, you are testing the integration of several units (Repository and Database connection). – Daniel W. Aug 17 '21 at 13:54
  • 1
    That’s fair, thanks for clarifying. I can definitely see your point of view. – thomasstuttard Aug 18 '21 at 19:48