python - 我将如何对这样的代码进行单元测试?

标签 python unit-testing testing oauth-2.0 pytest

我有以下类(class),目前正在通过运行调用此文件中方法的文件来测试它。然后,我混合使用打印语句和检查博客以确保代码有效。

我真的很想为此编写一些 pytest 单元测试并将其全部自动化,但我该怎么做呢?此外,如果身份验证不存在或变得无效,它会打开浏览器并提示用户输入授权代码。稍后这将由 gui 表单处理。 Pytest 不接受用户输入,这是正确的;它不会自动化。

class BloggerInterface(object):
    """Connects to blogger api and authorises client."""

    def get_credentials(self):
        """Gets google api credentials, or generates new credentials
        if they don't exist or are invalid."""
        scope = 'https://www.googleapis.com/auth/blogger'

        flow = oauth2client.client.flow_from_clientsecrets(
                'client_secret.json', scope,
                redirect_uri='urn:ietf:wg:oauth:2.0:oob')

        storage = oauth2client.file.Storage('credentials.dat')
        credentials = storage.get()

        if not credentials or credentials.invalid:
            auth_uri = flow.step1_get_authorize_url()
            webbrowser.open(auth_uri)

            auth_code = input('Enter the auth code: ')
            credentials = flow.step2_exchange(auth_code)

            storage.put(credentials)

        return credentials

    def get_service(self):
        """Returns an authorised blogger api service."""
        credentials = self.get_credentials()
        http = httplib2.Http()
        http = credentials.authorize(http)
        service = apiclient.discovery.build('blogger', 'v3', http=http)

        return service

    def get_blog(self, blog_id):
        """Gets the details ofthe blog withthe id blog_id"""
        BlogDetails = collections.namedtuple('BlogDetails', 'blog_id, name, desc, url')

        conn = self.get_service()
        request = conn.blogs().get(blogId=blog_id, view='ADMIN')
        response = request.execute()

        name = response.get('name')
        desc = response.get('description')
        url = response.get('url')

        blog = BlogDetails(blog_id=blog_id, name=name, desc=desc, url=url)

        return blog

    def get_posts(self, blog_id, status='live'):
        """Gets all posts from the blog with the id blog_id"""
        posts = []

        conn = self.get_service()
        request = conn.posts().list(blogId=blog_id, view='ADMIN',
        status=status)

        #Responses are paginated, so a paging loop is required.
        while request:

            response = request.execute()

            for post in response.get('items', []):
                post_id = post.get('id')
                title = post.get('title')
                url = post.get('url')
                status = post.get('status')
                content = post.get('content')

                posts.append({'post_id':post_id, 'title':title, 'url':url,
                    'status':status, 'content':content})

            request = conn.posts().list_next(request, response)

        return posts

    def add_post(self, blog_id, post, is_draft=True):
        """Adds a new post to the blog with the id blog_id"""
        conn = self.get_service()

        #post is in the form {title, content, (labels), author_name, author_id.
        title, content, author_name, author_id, labels = post

        data = {
                'kind': 'blogger#post',
                'title': title,
                'content': content,
                'labels': labels,
                'author': {'displayName':author_name, 'id':author_id}
                }

        request = conn.posts().insert(blogId=blog_id, body=data,
                isDraft=is_draft)
        response = request.execute()
        post_id = response.get('id')

        return post_id

最佳答案

不要测试 oauth2clientwebbrowser 项目。测试您的代码 如何对来自其他部分的输入和输出使用react。这些是黑盒子,您可以用自己的模拟替换它们,因此您可以看到您的代码如何响应不同的返回值。

使用 unittest.mock module产生模拟。如果您使用的是 Python < 3.3,请安装 backport mock project这样做。

例如,对于 BloggerInterface.get_credentials(),您模拟了 oauth2client.client.flow_from_clientsecrets()oauth2client.file.Storage()webbrowser.open()input。然后您可以使用 storage.get() 的响应来强制您的代码使用 webbrowser.open(),并测试您的代码是否正确尝试打开网络浏览器,然后调用 storage.put() 来存储凭据:

with mock.patch('oauth2client.client.flow_from_clientsecrets') as mockflow, \
        mock.patch('oauth2client.file.Storage') as MockStorage, \
        mock.patch('webbrowser.open') as mockwbopen, \
        mock.patch('yourmodule.input') as mockinput:
    # set the credentials to invalid
    storage = MockStorage.return_value
    credentials = storage.get.return_value
    credentials.invalid = True

    # run the method and see if we get what we want
    result = BloggerInterface().get_credentials()

    # check that the flow was initialised correctly
    mockflow.assert_called_with(
        'client_secret.json', 'https://www.googleapis.com/auth/blogger',
        redirect_uri='urn:ietf:wg:oauth:2.0:oob')
    MockStorage.assert_called_with('credentials.dat')

    # With invalid credentials, the code should obtain a auth url from the
    # flow, pass it to the browser. Then the authentication code should be taken
    # from input and passed back to the flow for exchange. Test these
    # interactions took place:
    flow.step1_get_authorize_url.assert_called_once_with()
    mockwbopen.assert_called_once_with(flow.step1_get_authorize_url.return_value)
    flow.step2_exchange.assert_called_once_with(mockinput.return_value)
    storage.put(flow.step2_exchange.return_value)
    assert result == flow.step2_exchange.return_value

关于python - 我将如何对这样的代码进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35958370/

相关文章:

python - 如何使用python找出http和ssl版本

python - 是否有一种编程方式可以在不通过电子邮件的情况下从 JIRA 检索通知?

Python 的 `unittest` 缺少 `assertHasAttr` 方法,我应该用什么代替?

ios - 在 Swift 中模拟具有泛型参数函数的类

javascript - 用诺克模拟 SOAP 服务

testing - QuickCheck:生成平衡样本的嵌套数据结构的任意实例

python - 创建一个 python 脚本来模拟 Matlab 文件并存储结果

python - 为什么我的 Python 实例被共享?

maven - jmeter 插件 maven test-jar

unit-testing - 使用 PHPUnit 组织 Selenium 测试的最佳方式是什么?