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.