Custom test suite for django app - django

I have a pretty complex django app which has following structure.
/myapp
/myapp/obj1/..
/myapp/obj1/views.py
/myapp/obj1/forms.py
/myapp/obj2/..
/myapp/obj2/views.py
/myapp/obj2/forms.py
/myapp/tests/..
/myapp/tests/__init__.py
/myapp/tests/test_obj1.py
/myapp/tests/test_obj2.py
I have a lot more objects. In /myapp/tests/__init__.py I import TestCase instances from test_obj1.py and test_obj2.py and it is enough to run all available test.
What I'm trying to do is to create a custom test suite. According to the documentation:
There is a second way to define the test suite for a module: if you
define a function called suite() in either models.py or tests.py, the
Django test runner will use that function to construct the test suite
for that module. This follows the suggested organization for unit
tests. See the Python documentation for more details on how to
construct a complex test suite.
So, i've created this function like this:
def suite():
suite = unittest.TestSuite()
suite.addTest(TestObj1Form())
suite.addTest(TestObj2Form())
return suite
However, when I run tests I get this error: ValueError: no such test method in <class 'myproject.myapp.tests.test_obj1.TestObj1Form'>: runTest. Of course I can define this method, but then if I run test it will invoke only this method and ignore all of the test* methods.
Any suggestions how to create a custom test suite for django app properly? I've googled and I found nothing about that.

You should add all your tests with a special function:
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestObj1Form))

Related

Pytest-Variables: how to use them without funcarg?

I wanna pass a json file for testbed definition to pytest.
My testcases are implemented inside a unittest class and need to use the json file send via pytest cli.
I tried to use pytest-variable to pass a json to pytest. Then I want to use the json as a dictionary inside my tests.
To be clearer, my test is launched with this command
pytest -s --variables ../testbeds/testbed_SQA_252.json TC_1418.py
I know unittest cannot accept external arguments but will be very useful a technique to unlock this constraint.
CASE 1 -- test implemented as functions --->OK
def test_variables(variables):
print(variables)
in this case the ouput is correct and the json is printed in the CLI
CASE 2-- test implemented as Unittest Class--->KO
class TC_1418(unittest.TestCase):
def setUp(self, variables):
print (variables)
....other functions
I obtain the following error:
TypeError: setUp() missing 1 required positional argument: 'variables'
Any Idea?
Your issue comes from mixing up concepts of pytest (e.g. injection of fixtures like variables) with concepts of unittest.TestCase. While pytest supports running tests based on unittest, I'm afraid that injection of plugins' fixtures into test methods is not supported.
There is a workaround though that takes advantage of fixtures being injected into other fixtures and making custom fixtures available in unittest.TestCase with #pytest.mark.usefixtures decorator:
# TC_1418.py
import pytest
import unittest
#pytest.fixture(scope="class")
def variables_injector(request, variables):
request.cls.variables = variables
#pytest.mark.usefixtures("variables_injector")
class Test1418(unittest.TestCase):
def test_something(self):
print(self.variables)
Notice that the name of the class starts with Test so as to follow conventions for test discovery.
If you don't want to go into this travesty, I propose you rather fully embrace Pytest and make your life easier with simple test functions that you have already discovered or properly structured test classes:
# TC_1418.py
class Test1418:
def test_something(self, variables):
print(variables)

Django DRF APITestCase chain test cases

For example I want to write several tests cases like this
class Test(APITestCase):
def setUp(self):
....some payloads
def test_create_user(self):
....create the object using payload from setUp
def test_update_user(self):
....update the object created in above test case
In the example above, the test_update_user failed because let's say cannot find the user object. Therefore, for that test case to work, I have to create the user instead test_update_user again.
One possible solution, I found is to run create user in setUp. However, I would like to know if there is a way to chain test cases to run one after another without deleting the object created from previous test case.
Rest framework tests include helper classes that extend Django's existing test framework and improve support for making API requests.
Therefore all tests for DRF calls are executed with Django's built in test framework.
An important principle of unit-testing is that each test should be independent of all others. If in your case the code in test_create_user must come before test_update_user, then you could combine both into one test:
def test_create_and_update_user(self):
....create and update user
Tests in Django are executed in a parallell manner to minimize the time it takes to run all tests.
As you said above if you want to share code between tests one has to set it up in the setUp method
def setUp(self):
pass

How to run a single test or single TestCase with django-nose?

With Django's normal test runner, you can drill down to run tests in a specific app, a specific subclass of TestCase, or a specific test within a specific subclass of TestCase.
E.g.:
./manage.py test myapp.MyTestCase.test_something
However, django-nose doesn't appear to support anything beyond testing a specific app. How do I replicate the last two behaviors?
Nose supports the following syntax (note : between test script name and test class name):
./manage.py test myapp.tests.test_script:MyTestCase.test_method
The correct answer is ./manage.py test myapp/tests/test_script:MyTestCase.test_method.
Using dots in the relative path did not work for me, but slashes did.

run every TestCase inside a module

How can you run tests from all TestCase classes, in a specific module under tests package?
In a Django project, I have split tests.py under tests/
Each file(module) has several TestCase classes, and each of them having several test methods.
init.py imports each of them.
I already know that I can do these:
Run all the test:
./manage.py test myapp
Or run specific TestCase:
./manage.py test myapp.OneOfManyTestCase
Or run very specific test method from a TestCase class:
./manage.py test myapp.OneOfManyTestCase.test_some_small_method
However, I can't figure out how to run every TestCases from a particular module.
Say, OneOfManyTestCase class is from tests/lot_of_test.py, and there are other test cases too.
Django doesn't seem to care about modules with TestCases.
How can I run all the TestCases inside lot_of_test?
I think to achieve this you need to subclass your own TestRunner from DjangoTestSuiteRunner and override build_suite method.
I ended up writing down my own TestSuiteRunner, like #sneawo said.
After Django-style fails, try importing as usual python-style.
One line to fix:
suite.addTest(build_test(label))
into
try:
suite.addTest(django.test.simple.build_test(label))
except ValueError:
# change to python-style package name
head, tail = label.split('.', 1)
full_label = '.'.join([head, django.test.simple.TEST_MODULE, tail])
# load tests
tests = unittest.defaultTestLoader.loadTestsFromName(full_label)
suite.addTests(tests)
and set TEST_RUNNER in settings.py:
TEST_RUNNER='myapp.tests.module_test_suite_runner.ModuleTestSuiteRunner'

GWT unit test for Activity and View

Does anybody have a link for a tutorial on how to write JRE junit tests (extending TestCase and not GWTTestCase) that tests Activity and Views in GWT 2.1?
Best regards
Pich
Views can only be unit tested using GWTTestCase because they call (either explicitly or implicitly) GWT.create().
To test Activities use mock Views to avoid use of GWT.create().
I have managed to test views, which of course contains reference to the objects that calls GWT.create(), using PowerMock.
For Activities it is easy todo using Mockito for instance to mock the View.