使用 moto 进行 SNS 模拟无法正常工作

red*_*888 3 python unit-testing boto amazon-web-services moto

在我的单元测试中:

def test_my_function_that_publishes_to_sns():
    conn = boto3.client("sns", region_name="us-east-1")
    mock_topic = conn.create_topic(Name="mock-topic")
    topic_arn = mock_topic.get("TopicArn")

    os.environ["SNS_TOPIC"] = topic_arn

    # call my_function
    my_module.my_method()
Run Code Online (Sandbox Code Playgroud)

正在测试的功能

# inside my_module, my_function...
sns_client.publish(
            TopicArn=os.environ["SNS_TOPIC"], Message="my message",
        )
Run Code Online (Sandbox Code Playgroud)

我收到错误:botocore.errorfactory.NotFoundException: An error occurred (NotFound) when calling the Publish operation: Endpoint with arn arn:aws:sns:us-east-1:123456789012:mock-topic not found

没有意义,这就是 moto 应该创建和嘲笑的主题。为什么说不存在呢?如果我 conn.publish(TopicArn=topic_arn, Message="sdfsdsdf")在单元测试本身内部调用它,它似乎会模拟它,但它不会模拟单元测试执行的 my_module.my_method() 。也许它太快地破坏了这个被嘲笑的话题?

编辑我尝试了各种方法,但得到了完全相同的错误:

# Using context manager
def test_my_function_that_publishes_to_sns():
    with mock_sns():
        conn = boto3.client("sns", region_name="us-east-1")
        mock_topic = conn.create_topic(Name="mocktopic")
        topic_arn = mock_topic.get("TopicArn")
    
        os.environ["SNS_TOPIC"] = topic_arn
    
        # call my_function
        my_module.my_method()


# Using decorator
@mock_sns
def test_my_function_that_publishes_to_sns():
    conn = boto3.client("sns", region_name="us-east-1")
    mock_topic = conn.create_topic(Name="mocktopic")
    topic_arn = mock_topic.get("TopicArn")

    os.environ["SNS_TOPIC"] = topic_arn

    # call my_function
    my_module.my_method()


# Using decorator and context manager
@mock_sns
def test_my_function_that_publishes_to_sns():
    with mock_sns():
        conn = boto3.client("sns", region_name="us-east-1")
        mock_topic = conn.create_topic(Name="mocktopic")
        topic_arn = mock_topic.get("TopicArn")
    
        os.environ["SNS_TOPIC"] = topic_arn
    
        # call my_function
        my_module.my_method()
Run Code Online (Sandbox Code Playgroud)

也打开了 GitHub 问题:https ://github.com/spulec/moto/issues/3027

小智 5

也许它会帮助您
将所有模块保留在一个类中,并在该类上放置一个装饰器@mock_sns来模拟sns,还将装饰器@mock_sns放在您初始化与sns连接的函数上。例子:

@mock_sns
class TestSnsMock(unittest.TestCase):

    @classmethod
    @mock_sns
    def setUpClass(cls):
        cls.conn = boto3.client("sns", region_name="us-east-1")
        cls.conn.create_topic(Name="some-topic")
        cls.response = cls.conn.list_topics()
        cls.topic_arn = cls.response["Topics"][0]["TopicArn"]

    def test_publish_sns(self):
        message = "here is same message"
        self.sns_client.publish(TopicArn=self.topic_arn, Message=message)


if __name__ == "__main__":
    unittest.main()
Run Code Online (Sandbox Code Playgroud)