Testing with CLU¶
CLU provides several tools to test actors. A typical example is as follows
import click
from clu.parser import command_parser
from clu.testing import setup_test_actor
@command_parser.command()
@click.argument('NAME', type=str)
async def greeter(command, name):
command.finish(text=f'Hi {name}!')
async def test_actor():
test_actor = setup_test_actor(LegacyActor('my_actor',
host='localhost',
port=9999))
# The following is not needed, start() is replaced with a MagicMock()
await test_actor.start()
# Invoke command and wait until it finishes
command = test_actor.invoke_command('greeter John')
await command
# Make sure the command finished successfully
assert command.status.is_done
# Get the last reply and check its "text" keyword
last_reply = test_actor.mock_replies[-1]
assert last_reply.flag == ':'
assert last_reply['text'] == 'Hi John!'
What setup_test_actor does is to replace the start method with a mock so that it’s not necessary to establish a real connection over TCP/IP. It also adds an invoke_command method that can be used to send test commands to the actor. Instead of replying via the normal actor channel, replies are stored in mock_replies as MockReply objects.
If using pytest, a normal design pattern is to define the test actor as a fixture
@pytest.fixture(scope='session')
async def test_actor():
_actor = setup_test_actor(LegacyActor('my_actor', host='localhost', port=9999))
yield _actor
# Clear replies
_actor.mock_replies.clear()
This usually requires instally pytest-asyncio to be able to define coroutines as fixtures.
setup_test_actor can be used with AMQPActor, JSONActor, and LegacyActor.
API¶
- class clu.testing.MockReply(command_id, user_id, flag, data={})[source]
Bases:
dictStores a reply written to a transport.
The data of the message is stored as part of the dictionary.
- class clu.testing.MockReplyList(actor)[source]
Bases:
listStores replies as
MockReplyobjects.- clear()[source]
Remove all items from list.
- async clu.testing.setup_test_actor(actor, user_id=1)[source]
Setups an actor for testing, mocking the client transport.
Takes an
actorand modifies it in two ways:Adds a
invoke_mock_commandmethod to it that allows to submit a command string as if it had been received from a transport.Mocks a client transport with
user_idthat is connected to the actor. Messages written to the transport are stored asMockReplyin aMockReplyListthat is accessible via a newactor.mock_repliesattribute.
The actor is modified in place and returned.
- Parameters
actor (clu.testing.T) –
user_id (int) –
- Return type
clu.testing.T