6

I'm testing a CRUD application written in L5 using Codeception acceptance tests. I was wondering how you guys go about this.

I originally thought I'd be able to use a CEST and use the @depends property to specify the order but it seems the auto DB cleanup is ran after each test, so after my insert the next test can't find that record in the DB.

Is there a way I can do this without specifically making up a DB dump specifically for testing?

I was hoping to be able to have the following tests in this order:

  • Create Item
  • Read Item
  • Update item
  • Delete Item

and check the DB at each stage to make sure it was successful.

Any help would be greatly appreciated.

Cheers, Daryll

3
  • I am also looking for something like this but specifically for some tests, for exaple, i want Test 2 to depend on Test 1 without making the tests in one function. I mean i want the changes of Test 1 to be persisted to test 2. Commented May 6, 2015 at 10:17
  • Checking DB is a horrible idea. Worked on a project that did that. Instead of testing your code you test. DB itself, PHP driver, DBLA and all of that is responsibility of creator of those components... As well as test bound to DB are very, very slow so your test at some point going to take forever. Commented Jun 1, 2016 at 17:13
  • As a fallow up to previous comment use DI and mocking of DBAL so you can make sure that proper methods are called. Do not check data. Commented Jun 1, 2016 at 17:14

2 Answers 2

6
+50

The default behaviour specified here is definitely what you want. You want the tests to be able to be performed in isolation. If you want to retest an area again, because it is broken, you don't have to go back and run your previous tests again to get it in the correct state to run the tests again.

A single broken test will give you a better idea of where the breakage is, rather than having multiple broken tests because a test that all your other tests depend on was broken, which is what the approach you are describing lends itself to.

If you think about it, say you are doing test driven development. You write a breaking test with the correct data that Creates a record. The other tests are to read, update, read again, delete the record, update a different record, create another new record, and read again. The delete fails, and the create and read tests fail because you reinsert the same index. The tests wont tell you that however, you just get 4 broken tests, and you will have to check all of your tests that are broken, and which one caused the other tests break, if that is indeed the case. You wont know.

If you do what the default behaviour tells you to do, you will have just the one broken test, and you fix the issue. Dead easy. You just add to the database as test cases arise to accommodate for them.

If you want to check what's in the database, you can do that by querying twice in the same test. Perform your update query then run your select query on what you have just done, and do and equals as another assertion. You can trust that the database has ran your query if you set it up correctly and get no errors, but you know your application better. Maybe you have triggers running, for instance.

I believe you can stop the behaviour with this sort of thing in a config, but its not what you want!:

class_name: FunctionalTester
modules:
    enabled: [Filesystem, FunctionalHelper, Laravel4, Asserts]
    config:
        Laravel4:
            environment: 'testing'
            cleanup: false
Sign up to request clarification or add additional context in comments.

2 Comments

I follow your logic, but isolating every single test is extremely demanding in a complex application. Say you refactor one component which affects the database and 10 other tests for which you now have to modify all the fixtures for all of them - which can be a tedious process! How do you manage that?
Good question: I'm guessing you've had to deal with a mocked out database and its corresponding fixtures, which is tedious, and an order of magnitude more complex. If your mock tests are broke, but your code is correct: your mocks haven't been refactored to "mimic" your new code. Rewriting mock code is tedious. Updating database fixtures isn't, just update your data with your gui and export to git, thats it. If your database tests break, your code is actually broken. Mocks break every time the code they mimic changes, and rewriting mocks is a step you dont need to do with your database test.
0

I have an experience on a large scale application where at some point a decision was maid to check DB on every test. 2 Years later world of pain and useless, slow, unmanageable tests. So lessons learned from that: Do not test data in DB on unittest.

Purpose of unit tests is to test code you wrote!

When you test that proper data got to DB you test:

  1. DBAL Driver (Larvel).
  2. PHP DB Driver (whatever larvel uses).
  3. DB itself (whatever DB).

That creates unnecessary complexity of test:

  1. Every test environment should have all those components properly setup.
  2. You need to make sure that data is consistent between tests. So easiest way is to clean data after every test and each test should create its own data(very slow).
  3. And you repeat work done by DB creators, Driver creators and Larvel ...

As a result: Tests getting slower, management of test environment gets harder. That leads to the point when you stop writing tests...

So solution is to write your classes to use DI and Mock DBAL on tests. There libraries that can help with DB mocking. But at the very end you should just test your code. That it calls proper functions with proper data and properly reacts to data that comes from DB.

And if you want to make sure that your DBAL works properly run it's unittest.

As for project I worked on there is an effort to move all test out of DB to mocks and speed improvements are x 1000 for tests that got changed.

1 Comment

But OP specifically stated that he's not writing unit, but acceptance tests..?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.