There are 2 types of tests in this project:
- Unit tests
- Defined in
*_test.go
files along the source code.
- Defined in
- QA (E2E) tests
- Defined in
test/qa
directory.
- Defined in
The following information or guidelines may not apply to the existing code written before introduction of this document.
Unit tests are the preffered way of testing. Generally all new code should be covered with unit tests. Well-grounded exceptions are allowed, but the code should still be written in a way so that as much as possible of it could be unit tested and the rest should be covered by QA tests.
Test categories are used to separate tests that interact with the environment from the ones that don't. Available categories are defined and documented in test/category/category.go
.
All unit tests must start with category.Set(t, category.XXX)
statement.
Table driven tests are the preferred way to test new functions as it's a convenient way to test all execution branches. On the other hand simple separate tests are okay too if that seems more convenient, but consider table driven ones if there's a lot of repeatability between tests.
The unit test coverage of newly written code should be >50%. That's just the mandatory bare minimum though, because generally it is expected that all of the code is covered.
Possible exceptions:
- Code that integrates with the OS and external libraries (keep such code minimal and mock such integrations in other tests)
Because the project uses many external dependencies, the usage of mocks in tests is wide spread.
- The mock of interface A used for testing can be defined in one of two places:
- In
*_test.go
file in a package that depends on the interface. - In
/test/mock/a.go
file (or/test/mock/a/a.go
if there are circular dependency issues) if the mock is exported.
- In
- Generally if the interface is big then it's better to export the mock so that it could be reused.
- A test reproducing a bug must be introduced prior to fixing the bug if possible (possible exceptions: bug reproduces only on untested distribution, etc.)
QA tests cover base app functionality and integrations. As they run slower than unit tests they shouldn't be used to cover the testing cases that can be covered by unit tests.
It is recommended to run these tests in Docker container, because they might change operating system environment unexpectedly. No persistent changes should be made though, so nothing that a reboot wouldn't fix.
In order to run QA tests, run test:qaDocker
or test:qaDockerFast
. It requires two arguments:
- name of the test category;
- pattern for test functions to run.
For test category names, check out test/qa directory. Name of the test suite would be
the name of the desired test file with test omitted. For test name, simply provide the desired
function name from that file. Test names are selected by pattern matching. Since all test function
names start with
test_
, simply usetest
as an argument to run every test in the suite.
For example, to run every test from the test_fileshare.py
category:
mage test:qaDocker fileshare test
And to run a single test:
mage test:qaDocker fileshare test_accept
To run tests without rebuilding everything each time use test:qaDockerFast
instead of
test:qaDocker
.
NA_TESTS_CREDENTIALS
environment variable is used to configure test credentials. It is a JSON
object containing a key(string):value(credentials) map.
QA tests use a list of the following keys:
default
- default account used for most of tests. In meshnet and fileshare tests is used as an account for "this" device.qa-peer
- account used for fileshare and meshnet tests for "another peer". This account will be invited by thedefault
account to its' meshnet. Check out qa peer README for more details.valid
- valid account used in login tests. It has to be different than default account.expired
- expired account is an account whose subscription has expired. Used in login tests.
Any of the used keys can be extended with NA_CREDENTIALS_KEY
environment variable which will be
appended to the used key.
E. g. when NA_CREDENTIALS_KEY
is set to my_key
, default_my_key
and qa-peer-my_key
will be
used instead of default
and qa-peer
in the executed tests.
Credentials structure consists of the following fields:
token *
- token to be used to log in during the QA test execution. It can be acquired in the nordvpn account dashboard.email
- email of the account to run tests with. In meshnet tests it is used to send and accept invitations. In other cases it is used for logging.password
- password of the account used in the login tests.
In case of meshnet tests(test_meshnet_*.py
), two NordVPN accounts might be required(qa-peer
and
default
). Meshnet functionality does not require a subscription, so a secondary free account can
be used in this case.
You can run unit tests for a single package as you would run uts for any other go project, for example:
cd nordvpn-app/meshnet
go test
We also have a mage targets for running tests for all of the packages:
test:cgoDocker
runs cgo tests.test:go
runs regular unit tests.
QA tests should generally cover app's use cases without necessarily covering all of the edge cases.
It's okay to introduce new QA tests on bug fixes as well if the bug is easier to reproduce that way.