Skip to content
Advertisement

Using unittests and moto to mock AWS

I am used to pytest approach for unit testing, without using classes. Today I wanted to give a try to unittest and I wanted to encapsulate my tests inside a TestCase.

Then consider this sample test class:

import unittest
import moto
import boto3

class TestMyClass(unittest.TestCase):
    @classmethod
    @moto.mock_ssm
    def setUpClass(cls) -> None:
        cls.ssm_client = boto3.client('ssm')
        cls.ssm_client.put_parameter(Name='test', Value='foo', Type='String')

    @moto.mock_ssm
    def test_something(self):
        value = self.ssm_client.get_parameter(Name='test').get('Parameter').get('Value')
        self.assertEqual(value, 'foo')

Why is not the parameter placed in setUpClass visible from the test? I could imagine that by using the @moto.mock_ssm decorator there it would all have been done in the mocked context.

I can, however, place the parameter within test_something as just:

@moto.mock_ssm
def test_something(self):
    self.ssm_client.put_parameter(Name='test', Value='foo', Type='String')
    value = self.ssm_client.get_parameter(Name='test').get('Parameter').get('Value')
    self.assertEqual(value, 'foo')

And then it (obviously) works. Why not with my first approach? I do not want to be populating the fake ssm parameter for each test that will rely on it. What is the best way of doing so here?

The reason why I am asking this is because the class I want to test requires this parameter when it is initialised.

Advertisement

Answer

The mock-decorators are scoped for that particular function, so data created inside that function will only be available there.

Instead, you can use the class-decorator:

import unittest
import moto
import boto3


@moto.mock_ssm
class TestMyClass(unittest.TestCase):

    client = None

    def setUp(self) -> None:
        self.client = boto3.client('ssm')
        self.client.put_parameter(Name='test', Value='foo', Type='String')

    def test_something(self):
        value = self.client.get_parameter(Name='test').get('Parameter').get('Value')
        self.assertEqual(value, 'foo')

Note that I’ve switched to setUp, instead of setUpClass. Because setUpClass is a classmethod, it is executed before the decorator is applied, and it will try to execute this method against AWS itself.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement