Writing tests for actors¶
The Leapp framework provides support for easily writing unit and component tests for actors and also allows easy execution of the whole actors within those tests. See this document to find out what is the difference between unit and component tests.
Getting started with writing tests¶
Tests are considered being part of the actor and we do not only encourage but basically require you to write tests if you want the actors to be accepted into the git repository. To read more about what we ask from you when submitting your work for our review, see Contributing guidelines for writing actors.
Tests for an actor are to be placed within the actor‘s directory, in a
subdirectory called tests
. The layout for an actor MyActor
in the
repository could look like this:
actors\
myactor\
actor.py
tests\
component_test_my_actor.py
unit_test_my_actor.py
Naming conventions¶
To have the tests found and carried out by pytest framework, all test functions have to:
- reside in
test_*.py
or*_test.py
files, - be prefixed by
test_
. - test modules should have unique names, and we use the following convention
test_*_{actor_name}.py
. For example:test_unit_sctpconfigread.py
orcomponent_test_sctpconfigread.py
See the pytest documentation.
Writing tests that execute the whole actor - component tests¶
Now let‘s assume you want to write a test that executes the actor. This is how
your component_test_{actor_name}.py
from above could look like:
def test_actor_execution(current_actor_context):
current_actor_context.run()
This example makes use of the current_actor_context
fixture and will execute the MyActor
actor.
Now if you would want to check that it produced an imaginary model called
ProducedExampleModel
you can check this with the help of the consume
method.
from leapp.models import ProducedExampleModel
def test_actor_execution(current_actor_context):
current_actor_context.run()
assert current_actor_context.consume(ProducedExampleModel)
If your actor requires input data that it can consume, you can specify the
input data with the help of the feed
method of the current_actor_context
fixture.
from leapp.models import ConsumedExampleModel, ProducedExampleModel
def test_actor_execution(current_actor_context):
current_actor_context.feed(
ConsumedExampleModel(value=1),
ConsumedExampleModel(value=2))
current_actor_context.run()
assert current_actor_context.consume(ProducedExampleModel)
assert current_actor_context.consume(ProducedExampleModel)[0].value == 3
In case your actor uses ConfigModel
for consuming workflow specific configuration, run the actor in the test as:
current_actor_context.run(config_model=ConfigModel(os_release=OSRelease()))
Fixtures¶
The unit testing support was first implemented with the help of
pytest fixtures.
Nowadays, we encourage you to use only the current_actor_context
fixture
mentioned above. However the other fixtures have been preserved and are
still possible to use - see their documentation.
Testing actors that modify the OS¶
Replace the functions that read or modify the system with functions that do
not alter the system and return what you specify in the test. This is called
mocking. Currently it is not possible to mock any function while using the
current_actor_context.run()
. But, mocking is possible in an actor‘s library.
For that, read further.
Testing private actor library - unit tests¶
Leapp allows actors to relocate their code into actor private library. This
allows for better testability since the current implementation of Leapp does
not allow tests to import anything from the actor.py
. Thus the code that is
supposed to be unit tested is necessary to move into the actor‘s private
library. Modules from the private library can then be imported not only from
the actor.py
but also from the test modules.
Let‘s assume your actor has a private library module called
private_{actor_name}.py
.
actors\
myactor\
actor.py
libraries\
private_myactor.py
tests\
unit_test_my_actor.py
And the private_my_actor.py
looks like this:
def my_function(value):
return value + 42
You can easily write a test for this library like this:
from leapp.libraries.actor import private_my_actor
def test_my_actor_library():
assert private.my_function(0) == 42
assert private.my_function(1) == 43
assert private.my_function(-42) == 0
Using repository resources during test runtime¶
It is possible to test other things in the repository your actor is in and in the linked repositories. For example you may want to test shared libraries, models, etc.
from leapp.libraries.common import useful_library
from leapp.models import ExampleModel, ProcessedExampleModel
def my_repository_library_test():
e = ExampleModel(value='Some string')
result = shared.process_function(e)
assert type(result) is ProcessedExampleModel
Actors‘s test dependencies¶
If your actor‘s tests require a special package for their execution, create a
Makefile in the actor’s root directory with an
install-deps
target calling yum install -y
.
$ cat actors/myactor/Makefile
install-deps:
yum install -y my-tests-need-this-pkg
Note: Dependencies defined the way mentioned above is for test execution only. If your actor requires any package when executed as part of a workflow, it needs to be specified in a leapp-repository specfile.
Running the tests¶
Preparing the environment¶
To execute unit tests of actors from all Leapp repositories in the
leapp-repository
GitHub repository, you need to install test dependencies for all
actors by running make install-deps
.
Actor‘s tests¶
Makefile of leapp-repository
provides target for testing your actors.
Issue make test
in the root directory of the leapp-repository
GitHub repository
to test all actors.
You can also run tests by simply running pytest
To test specific actor using makefile, set ACTOR
environment variable:
ACTOR=myactor make test
or
pytest {PATH_TO_ACTOR}
It is also possible to run only selected tests based on their name:
pytest -k "vim" # to run all tests contains vim in name
pytest -k "not vim" # to run all tests, which not contains vim in name
More examples could be found in the pytest documentation