【问题标题】:Unit testing and mocking email sender in Python with Google AppEngine使用 Google AppEngine 在 Python 中进行单元测试和模拟电子邮件发件人
【发布时间】:2009-01-09 08:33:34
【问题描述】:

我是 python 和应用引擎的新手。

我有这段代码在一些身份验证逻辑之后根据请求参数发送电子邮件。在我的单元测试中(我正在使用GAEUnit),如何确认已发送包含特定内容的电子邮件? - 即我如何用假电子邮件来模拟电子邮件以验证发送被调用?

class EmailHandler(webapp.RequestHandler):
 def bad_input(self):
  self.response.set_status(400)
  self.response.headers['Content-Type'] = 'text/plain'
  self.response.out.write("<html><body>bad input </body></html>")

 def get(self):
  to_addr = self.request.get("to")
  subj = self.request.get("subject")
  msg = self.request.get("body")
  if not mail.is_email_valid(to_addr):
    # Return an error message...
    #   self.bad_input()
    pass

  # authenticate here

  message = mail.EmailMessage()
  message.sender = "my.company@gmail.com"
  message.to = to_addr
  message.subject = subj
  message.body = msg
  message.send()
  self.response.headers['Content-Type'] = 'text/plain'
  self.response.out.write("<html><body>success!</body></html>")

还有单元测试,

import unittest
from webtest import TestApp
from google.appengine.ext import webapp
from email import EmailHandler

class SendingEmails(unittest.TestCase):

  def setUp(self):
    self.application = webapp.WSGIApplication([('/', EmailHandler)], debug=True)

  def test_success(self):
    app = TestApp(self.application)
    response = app.get('http://localhost:8080/send?to=vijay.santhanam@gmail.com&body=blah_blah_blah&subject=mySubject')
    self.assertEqual('200 OK', response.status)
    self.assertTrue('success' in response)
    # somehow, assert email was sent 

【问题讨论】:

  • 感谢 GAEUnit 的链接。我一直在寻找这样的东西。

标签: python unit-testing google-app-engine mocking


【解决方案1】:

您还可以覆盖 AppEngine 内 mail_stub 中的 _GenerateLog 方法。

这是一个父 TestCase 类,我在测试是否发送电子邮件时用作 mixin:

from google.appengine.api import apiproxy_stub_map, mail_stub

__all__ = ['MailTestCase']

class MailTestCase(object):
    def setUp(self):
        super(MailTestCase, self).setUp()
        self.set_mail_stub()
        self.clear_sent_messages()

    def set_mail_stub(self):
        test_case = self
        class MailStub(mail_stub.MailServiceStub):
            def _GenerateLog(self, method, message, log, *args, **kwargs):
                test_case._sent_messages.append(message)
                return super(MailStub, self)._GenerateLog(method, message, log, *args, **kwargs)

        if 'mail' in apiproxy_stub_map.apiproxy._APIProxyStubMap__stub_map:
            del apiproxy_stub_map.apiproxy._APIProxyStubMap__stub_map['mail']

        apiproxy_stub_map.apiproxy.RegisterStub('mail', MailStub())

    def clear_sent_messages(self):
        self._sent_messages = []

    def get_sent_messages(self):
        return self._sent_messages

    def assertEmailSent(self, to=None, sender=None, subject=None, body=None):
        for message in self.get_sent_messages():
            if to and to not in message.to_list(): continue
            if sender and sender != message.sender(): continue
            if subject and subject != message.subject(): continue
            if body and body not in message.textbody(): continue
            return

        failure_message = "Expected e-mail message sent."

        args = []
        if to: args.append('To: %s' % to)
        if sender: args.append('From: %s' % sender)
        if subject: args.append('Subject: %s' % subject)
        if body: args.append('Body (contains): %s' % body)

        if args:
            failure_message += ' Arguments expected: ' + ', '.join(args)

        self.fail(failure_message)

之后,示例测试用例可能如下所示:

import unittest, MailTestCase

class MyTestCase(unittest.TestCase, MailTestCase):
    def test_email_sent(self):
        send_email_to('test@example.org') # Some method that would send an e-mail.
        self.assertEmailSent(to='test@example.org')
        self.assertEqual(len(self.get_sent_messages()), 1)

【讨论】:

  • 查看gae-testbed.googlecode.com,它提供了执行此操作的基类。
  • 这个项目看起来很有希望。我希望您已经可以提供教程,尤其是用于测试 Mail API 的教程。
【解决方案2】:

一个非常简短的介绍提供PyPI: MiniMock 1.0。这是一个用于建立模拟的非常小的库。

  1. 将你的 mock 注入到应该被 mock 的模块中
  2. 定义,您的模拟将返回什么
  3. 调用方法
  4. 您的模拟会显示调用了哪个方法。

祝你好运!

【讨论】:

    【解决方案3】:

    只需使用以下命令获取自激活邮件存根后发送的所有消息。

    from google.appengine.api import apiproxy_stub_map
    sent_messages = apiproxy_stub_map.apiproxy._APIProxyStubMap__stub_map['mail'].get_sent_messages()
    

    【讨论】:

      【解决方案4】:

      Google 在他们的documentation 中有一个非常简单的方法来做到这一点。

      您在设置中创建一个测试平台和邮件存根,如下所示:

      self.testbed = testbed.Testbed()
      self.testbed.activate()
      self.testbed.init_mail_stub()
      self.mail_stub = self.testbed.get_stub(testbed.MAIL_SERVICE_NAME)
      

      运行你的方法,然后像这样检查它:

       messages = self.mail_stub.get_sent_messages(to='alice@example.com')
       self.assertEqual(1, len(messages))
       self.assertEqual('alice@example.com', messages[0].to)
      

      【讨论】:

        【解决方案5】:

        我在 GAEUnit 中使用了 jgeewax 的 GAE 测试平台。使用 GAEUnit 代替 NoseGAE 对我来说更容易,因为我已经安装了 GAEUnit。步骤如下:

        将 GAEUnit 添加到您的应用中

        1. its Google Code project hosting page 下载 GAEUnit 的压缩存档。
        2. 解压存档。
        3. 从存档中提取的文件夹中,将gaeunit.py 复制到应用的根文件夹中。
        4. 将以下 2 行添加到您的 app.yaml 中,在 handlers: 行的正下方:

        代码:

        - url: /test.*
          script: gaeunit.py
        

        (可选)从存档中提取的文件夹中,有一个名为 sample_app 的文件夹,其中包含 webtest 模块的修改版本。将webtest 模块(包含debugapp.py__init__.py 的整个文件夹)复制到应用的根目录。

        将 GAE 测试平台添加到 GAEUnit:

        1. its Google Code project hosting page 下载 GAE Testbed tar gzip 压缩包。
        2. 解压存档。
        3. 解压后的存档中有gaetestbed 模块(它是名为“gaetestbed”的文件夹)。将模块复制到应用的根目录。
        4. 在应用程序根目录的 test 文件夹中创建一个文件。为了这个例子,我们把它命名为test_mailer.py
        5. 使用 GAE Testbed Google Code 项目托管页面中的示例,将以下行添加到 test_mailer.py

        代码:

        import unittest
        from gaetestbed import MailTestCase
        
        class MyTestCase(MailTestCase, unittest.TestCase):
            def test_email_sent(self):
                send_email_to('test@example.org') # Some method that sends e-mail...
                self.assertEmailSent(to='test@example.org')
                self.assertEqual(len(self.get_sent_messages()), 1)
        

        启动您的服务器并转到http://localhost:8080/test。您应该注意到(额外的)1/1 测试是从 http://localhost:8080/test 运行的。

        来源:Using GAE Testbed with GAEUnit: Testing that email was sent

        【讨论】:

          猜你喜欢
          • 2018-02-22
          • 2011-10-05
          • 2019-01-29
          • 2011-07-12
          • 1970-01-01
          • 1970-01-01
          • 2014-11-04
          • 2012-07-22
          • 1970-01-01
          相关资源
          最近更新 更多