I cloned my database, and I right now, I tested inserting new customer to database. What I want is to return his automatically generated customer_id, and to use it on other tests outside of the class
Assuming you cloned the database to have a database for testing and this is where the need of such a customer_id (and potentially more of such key data-points like IDs of all kinds) grows from.
Such a test database is commonly called a Test Fixture or just Fixture in short. You want to run your tests with that fixture, in your case the test-database.
Without looking right now what this implies for your tests first, I'd like you to point to the Phpunit documentation which describes how Phpunit supports Test Fixtures:
You will find a way to setUp each test. As you can extend the base TestCase, you can make it a template for all of your tests that extend from a base test-case you introduce yourself in your test-suite.
In the very simplistic example, it could look like:
abstract class CustomerDatabaseTestCase extends TestCase
{
protected $customer_id;
public function setUp(): void
{
$this->customer_id = 42; /* PUT YOUR MAGIC NUMBER HERE */
}
}
Extending from that test-case then allows you to access the customer id by $this->customer_id within your tests.
At the end of the day, this is just standard PHP object oriented programming and follows the rule of the language in regards of inheritance and visibility.
@depends is not (well) fitting in your scenario, as you have a true fixture and you don't want to make individual test-methods depend on other test-methods, because you also want to execute these test-methods isolated to each other (sooner or later) and introducing @depends make them dependent and therefore will stand in your way to this regard.
Now so much on the very general level how you could do this.
Using a base-test-case you control your own allows you to group test-code and also to control the fixture. If you read the Phpunit documentation regarding this carefully you'll already get some pointers what (heavy) fixtures can lead to, as there is no free lunch.
So lets look a little bit why, even we start to realize that fixtures can become a burden, we still do them if needed. And that is because the benefit of running the tests is running them automated.
Automated tests allow us to (more or less) quickly iterate with the development while running the tests. We get direct and fast feedback.
We even do this while we know that fixtures can become a burden here. Take a test-database as an example: One test inserts a record while another test needs that record to test something different. So a fixture can become brittle or heavy and/or expensive by itself.
While one way then is to reduce the fixture, e.g. you could only extend those test-cases from the database-base-test-case that are actually database related tests, another (and both ways aren't exclusive to each other) is to automate the setup of your test-database so that once your overall test-fixture went dangling, you have an automated way to setup the fixture and it is always (at least) well defined - like always.
For example, you could add a bootstrap file in Phpunit that takes care of setting up the test database as well. While you could do that in the setUp method of the database-base-test-case, you'll soon notice that it runs before every test-method. So if you need to do expensive operations there (like setting up the test-database takes some seconds), the run-time of each test would be enlarged by that amount of seconds. Multiply it with the number of tests and you'll find the overall run-time of your test-suite to grow fast.
A larger run-time of your tests then degrades the overall progress as you don't get feedback fast any longer which is one of the key drivers to do the Phpunit tests in the first place.
Therefore the topic of Fixtures is not an entirely easy one. Especially with more heavy systems under test - e.g. a big test-database - you'll face the reality and the need to find a good compromise for those tests depending on a fixture. The good news is, as the tests run automated, you can play fast here as well and check with the run-time of the test-suite immediately if a change of your tests is of benefit or not which allows you to make decisions of change fast.
- First try your tests to not need a fixture at all.
- If not possible try to keep the fixture low.
- Only use
@depends when you need a certain order for the test-methods (e.g. first creating a database row, then operating on it in the second test method). Try to prevent that as well.
- Have the setup of any test-database automated so that you can run the test-suite as if it didn't exist before that run (and that running the tests can damage or even fully destroy it in case of an error).
If you use a library for database access, also check with the library documentation which test-utilities it provides. A good library has test-adapters or at least test-support so that you can lean more towards (faster and less brittle) unit-tests instead of the need to write (more heavy, slower and maintenance intensive) integration tests (see the test-pyramid and learn why integration tests can lead to a "testing tarpit").
The Phpunit documentation also has some good key pointers how to design ones own test-suite to get and keep having benefits of running a test-suite.
And some word of warning just so that I have made this clear: If you search for Phpunit on SO, keep an eye how many are asking about testing with databases. It is easy to run into more complicated problems with it (Test Fixtures !).
This should be taken as a sign. If code is hard to test, consider changing the design of your code so that it becomes easy to test (have the overall test-suite run in seconds, not minutes). Focus on your production code, not the test-code, so do these changes only with the littlest modifications to the test-suite itself as it is a central development dependency and if it breaks, you will stop testing until you fix it. So it can easily become a show stopper. This is to be avoided at all costs and with as little cost as necessary.
Happy testing.
@dependsmay be messy and tricky but making your tests depend on database values from other tests will be worse. I usually reset the test database between tests and create the test data in each test so the db state is always known and controlled.createCustomer()method and acreateAddress()method with aCustomer $customerargument.