Currently I am doing TDD on a reusable Django app. One test should make sure that my view only returns articles that have a publish-date that is in the past. I am quite new to testing in Django. So far I have learned how to use .json files as fixtures for my test classes.
However for this test I do not want to insert publish dates that are 1000 years in the future. After all another species might discover our ancient internet, check out my source and wonder why my test fails :) What other approaches are there to solve this problem? Static .json files seem to be a bit hard to maintain as well as the application grows... mocking the datetime.datetime.now() method in my tests feels tedious as well.
There must be an easy way to produce the .json fixture on the fly before the test runs and always have 2 days from now as the publish-date for some of my entries...
You could try subclassing the datetime functions (see "Using Mock objects in Django for testing the current date").
Mocking datetime was my first thought as well but as LaundroMat pointet out in his blog post himself, this is rather hacky and bad.
I came up with another solution:
I just gave up on .json fixtures. I don't even know why Django encourages to use them. They look ugly and they are impossible to maintain.
Instead I added a module test_data.py to my fixtures folder. That module imports my models and defines some nice methods that create test-data for me. In my tests.py I dropped the fixtures = ['some_json_file'] line and added a setUp() method instead. This method executes my 'dynamic fixtures' from my test_data.py module.
This is so simple and obvious that I wonder if there is anything wrong with this approach. If no one comments on this solution, I will mark is as accepted in a couple of weeks or so...
You can try using django dynamic fixture, it will fill date/time properties automatically for you.
Creating test data
Indeed it is far more flexible to create your test data with Python.
There are several packages that support such things, for instance
model-backery
django-dynamic-fixture
These two use fairly different approaches. Have a look and pick the one you like more.
You can also write data generation functions from scratch. If you partition your logic carefully, this is not overly cumbersome.
Handling time
For tests involving time, the right approach is indeed mocking -- but don't do it yourself, use a nice library. See for instance
freezegun
There is even a pytest plugin for it.
Related
I am currently deciding what testing packages to use with my django project, specifically how to populate data before I run tests. I have looked into:
Fixtures: Many people seem to be against this since modifying JSON can be difficult and hard to maintain.
Factory boy: My project has a lot of hierarchy to it, so I feel like creating an object from a model that is really low in the hierarchy is really slow.
The idea I have in my mind is to just make a database that I will always run tests against. Since I know what data is in it, shouldn't it work similarly to fixtures without the hassle of JSON? Since I haven't seen this idea through my research, I assume this is a bad idea. Why is it a bad idea though?
Did you actually test with factory boy? With an in-memory sqlite database it is very fast, in my experience, and super convenient with hierarchies.
Your database idea is more or less the same as fixtures -- you could use the database to create JSON fixtures by running the dumpdata management command on it, and maintain your test data in the database instead of in the JSON files.
Some reasons to prefer factory boy over a test database:
The data is generated right there in the test, so it's immediately obvious what happens and which fields are relevant for the test.
The data comes with the test code, no extra files or database dumps to manage.
Factory boy is very good with hierarchies ("I want an instance of this instance with all fields the default value, except this one field six steps up in the hierarchy" -- instance = InstanceFactory.build(series__study__patient__archive__project__algorithm_type='foo'))
Sometimes an object doesn't have to be saved to the database at all to have its methods tested, in that case factory boy's .build() is very fast.
Instead of picking interesting border cases for the current test, you will be tempted to just re-use the stuff you already have in the database and not find bugs.
Maybe the different values you need to test with can't exist in the database at the same time due to uniqueness constraints.
There are probably more, but I need to sleep.
I am very new to TDD and am trying to create my first Djagno application with tests. I am a bit confused when it comes to generic views. I have read several places (including the official docs) that each view should have tests associated with it. But I have also read that you should avoid testing Django internals because it is unnecessary.
So if I have a view like this:
class ClinicView(DetailView):
model = Clinic
template_name = "directory/clinic.html"
which uses a generic view and works fine, should I write a test for it?
My gut feeling is that I shouldn't have to because I use a generic view but haven't really found much to tell me if my feeling is correct. What are the best practices when it comes to this? Or what would be expected of me if I was to be giving my code over to be maintained by someone else? Should I at least write a test to make sure that my model and the template exist? Thanks in advance.
You want to avoid over-testing. You should only write tests for custom logic or for things that change frequently.
For example, if the Clinic model had a complex method which calculated some result, you would want tests to ensure this does what you think it does.
If you had something that you changed often and others may come in and change, you want tests to ensure that it is still functional after your change. The Django views are already tested. Unless you add a bunch of custom logic to the View (which you should probably be putting in a ModelManager anyway) there's no point to test it repeatedly with automated tests.
Testing is great and I love it! But I hate maintaining it, so I don't aim for full coverage. Once you cover your custom code with tests, you get diminishing returns by testing every little piece.
I once worked for a company that went a little crazy and wanted me to write tests for the automated tests. Don't be like them (:
I know there are existing tools for testing a ColdFusion application (MXUnit, MockBox), but I'm creating a custom tool, so that it will require less configuration.
When I run a unit test file, it's done via a generic 'model' which retrieves all functions from the unit test file. Within each test function, I have to call assertEquals -- but these functions are in the model, so I cannot access them.
I tried by passing the model itself to the unit test file so it can call the models functions directly but it doesn't work and it adds logic to the test file, which I don't like.
I can also extend the model in the test file but I will have to call directly the test file, call super.init(this) so the model can fetch test functions, etc..
Is there a way to achieve this kind of process? What's the best option?
In answer to your question, it sounds like you want to inject variables / methods into the subject under test. You can do it like so:
myInstance["methodName"] = myFunction;
You can then call the injected method like so:
myInstance.myFunction();
Both MXUnit and TestBox use this technique.
Having said that I don't quite understand why you want to re-invent the wheel. TestBox is an excellent, proven testing framework which has a wealth of features which would take you an incredible amount of time to replicate. I'm not quite sure what the configuration issue you have could be - it really doesn't require very much setup. Maybe it might be worth asking how to setup and use TestBox rather than how to build your own testing solution :)
There is a good book (which is available in a free version) which you can read on TestBox here : http://testbox.ortusbooks.com/
Good luck!
I wish to test basic CRUD operations in CakePHP (1.3) using SimpleTest.
For example, I wish to add a new record, and make sure that I get an error message if validation fails and a new record if save goes well.
Is it better to write these tests as (1) Controller tests for the relevant action (e.g. add()), or as (2) Web Tests, using $this->post() or $this->setField()?
This is an old question but still no answer so I'll give it a shot...
I believe that the first thing you need to do is separate your concerns better. Right now what you're doing, at least to me, is a code smell...meaning something ain't right!
How did I come to this conclusion?
Well, the question you asked and how you're answering it. The question that you're asking is:
"How should I test a model's functionality?"
Your answer:
"Test it from the controller or the view"
So, the first thing I would do is setup a method in the appropriate model to do what you're wanting. Write out the code that you think you need. Save a record and return the appropriate values that you're looking for based off whatever conditional statements you come up with.
After that I'd setup some fixtures so you have some data to test against. You can learn more about CakePHP fixtures and how to create them at the CakePHP manual, http://book.cakephp.org/view/1201/Preparing-test-data (In future projects I'd make the fixtures first, but that's just a personal preference)
Once your fixtures are setup you can actually go ahead and test your new model method. Testing models, in my opinion, is the easiest to test in CakePHP. I won't go into the details here, only because the CakePHP manual, http://book.cakephp.org/view/1207/Testing-models, has a bunch of info about how to test models.
At this point you should have a properly unit tested model action and concerns properly being separated.
That being said if you're feeling super spunky and want your code tested from all angles then by all means, setup a controller test to ensure the action is performing correctly. Setup a web test to ensure the whole package is working together.
First though, separate your concerns.
I recently got PHPUnit working with xDebug for testing my Zend Framework applications. The fact I use ZF shouldn't make any difference to this question- just mentioned it for completeness.
Anyway, it all works fine, but now I want to set up an in-memory database using PDO SQLite. I have done this successfully and have created tables and inserted data. However this task seemed to take ages, the syntax from my Export did not match SQLites needs so I had to play around for a while.
Also SQLite does not support constraints (is that right?) which my application does use, so the whole process seems a waste of time if I cannot test my constraints.
Is using SQLite the right solution to my problem? Does anyone have any better ways of using it or any other DB solution to unit testing?
The idea of unit tests is to test smaller parts, so one way could be to work with small amounts of (static) sample data, for example as described in http://www.phpunit.de/manual/3.4/en/database.html
If you really need to test against a full database with all it's constraints, I think there is no way around just using the specific database of your application, for example MySQL.