-
-
Notifications
You must be signed in to change notification settings - Fork 79
Writing Tests
Tests are located in the tests
folder. We only have unit tests in the project for now.
For unit tests, we use pytest and pytest-it. If you are not familiar with these tools, please take a quick look at their official docs, it might help you:
Unit tests are located in the tests/unit
folder.
Test files should follow the same structure as the project itself and their names should start with test_
. For example:
- File:
scanapi/evaluators/code_evaluator.py
. Test Filetests/unit/evaluators/test_code_evaluator.py
- File:
scanapi/scan.py
. Test file:tests/unit/test_scan.py
If the test file gets too long, we create a folder and split the tests there. For example:
- File:
scanapi/tree/endpoint_node.py
. - Test Files:
tests/unit/tree/endpoint_node/test_delay.py
tests/unit/tree/endpoint_node/test_get_requests.py
tests/unit/tree/endpoint_node/test_get_specs.py
- ...
We create a separate class for each method we want to test. We add two describe
decorators for this test class:
- one for the class name that the method belongs to;
- another for the method name itself.
We use context
decorators to specify different scenarios. And, we use the it
decorator for every test case, to describe what is the expected behavior.
Let's say we have the following file to be tested:
# my_file.py
class MyClassA:
def method_1(self):
pass
def method_2(self):
pass
class MyClassB:
def method_3(self):
pass
The test file test_my_file.py
would look like something similar to this:
from pytest import mark
@mark.describe("my class a")
@mark.describe("method_1")
class TestMethod1:
@mark.context("when scenario A happens")
@mark.it("should do this")
def test_should_do_this(self):
# test here
pass
@mark.context("when scenario A happens")
@mark.it("should not do that")
def test_should_not_do_that(self):
# test here
pass
@mark.context("when scenario B happens")
@mark.it("should do another thing")
def test_should_do_another_thing(self):
# test here
pass
@mark.describe("my class a")
@mark.describe("method_2")
class TestMethod2:
@mark.context("when scenario C happens")
@mark.it("should do something")
def test_should_do_something(self):
# test here
pass
@mark.context("when scenario D happens")
@mark.it("should do another thing")
def test_should_do_another_thing(self):
# test here
pass
@mark.describe("my class b")
@mark.describe("method_3")
class TestMethod3:
@mark.context("when scenario E happens")
@mark.it("should do something")
def test_should_do_something(self):
# test here
pass
@mark.context("when scenario F happens")
@mark.it("should do another thing")
def test_should_do_another_thing(self):
# test here
pass
The output for this would be like:
* tests/unit/test_my_file.py...
- Describe: My class a...
- Describe: Method_1...
- Context: When scenario a happens...
- ✓ It: should do this
- ✓ It: should not do that
- Context: When scenario b happens...
- ✓ It: should do another thing
- Describe: Method_2...
- Context: When scenario c happens...
- ✓ It: should do something
- Context: When scenario d happens...
- ✓ It: should do another thing
- Describe: My class b...
- Describe: Method_3...
- Context: When scenario e happens...
- ✓ It: should do something
- Context: When scenario f happens...
- ✓ It: should do another thing
Sometimes we have files without classes. It is not a problem, we can change the describe
decorator to point out the file name
Let's say we have the following file to be tested:
# `my_file.py`
def method_1(self):
pass
def method_2(self):
pass
The test file test_my_file.py
would look like something similar to this:
from pytest import mark
@mark.describe("my file")
@mark.describe("method_1")
class TestMethod1:
@mark.context("when scenario A happens")
@mark.it("should do this")
def test_should_do_this(self):
# test here
pass
@mark.context("when scenario A happens")
@mark.it("should not do that")
def test_should_not_do_that(self):
# test here
pass
@mark.context("when scenario B happens")
@mark.it("should do another thing")
def test_should_do_another_thing(self):
# test here
pass
@mark.describe("my file")
@mark.describe("method_2")
class TestMethod2:
@mark.context("when scenario C happens")
@mark.it("should do something")
def test_should_do_something(self):
# test here
pass
@mark.context("when scenario D happens")
@mark.it("should do another thing")
def test_should_do_another_thing(self):
# test here
pass
The output for it would be like:
* tests/unit/test_my_file.py...
- Describe: My file...
- Describe: Method_1...
- Context: When scenario a happens...
- ✓ It: should do this
- ✓ It: should not do that
- Context: When scenario b happens...
- ✓ It: should do another thing
- Describe: Method_2...
- Context: When scenario c happens...
- ✓ It: should do something
- Context: When scenario d happens...
- ✓ It: should do another thing
Do you wanna see real examples? Check the folder https://github.com/scanapi/scanapi/tree/master/tests/unit