10

webapp2 ハンドラーをテストしようとしています。これを行うには、ハンドラーにリクエストを送信することをお勧めします。

request = webapp2.Request.blank('/')
# Get a response for that request.
response = request.get_response(main.app)

問題は、応答がほとんど HTML などの束に過ぎないことです。

HTML に変換される前に、ハンドラーから jinja2 テンプレートに渡されたものを確認したいと思います。

ハンドラー クラス コード内の状態でテストを実行したいと考えています。特定の変数が応答ハンドラーでどのように見えるかを確認したくないので、render_to_response() に渡される前に dict テンプレートがどのように見えるかを確認したい

これらの変数の値が正しいことをテストしたいと思います。

これまでのテスト コードは次のとおりですが、response = request.get_response() は、生の変数ではなく、大量の html を提供するだけなので、行き詰っています。

import unittest
import main
import webapp2

class DemoTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testNothing(self):
        self.assertEqual(42, 21 + 21)

    def testHomeHandler(self):
        # Build a request object passing the URI path to be tested.
        # You can also pass headers, query arguments etc.
        request = webapp2.Request.blank('/')
        # Get a response for that request.
        response = request.get_response(main.app)

        # Let's check if the response is correct.
        self.assertEqual(response.status_int, 200)
        self.assertEqual(response.body, 'Hello, world!')


if __name__ == '__main__':
    unittest.main()

ここに私のハンドラがあります:

class HomeHandler(BaseHandler):
    def get(self, file_name_filter=None, category_filter=None):
        file_names = os.listdir('blog_posts')
        blogs = []

        get_line = lambda file_: file_.readline().strip().replace("<!--","").replace("-->","")

        for fn in file_names:
            with open('blog_posts/%s' % fn) as file_:
                heading = get_line(file_)
                link_name = get_line(file_)
                category = get_line(file_)

            date_ = datetime.strptime(fn.split("_")[0], "%Y%m%d")

            blog_dict = {'date': date_, 'heading': heading,
                         'link_name': link_name,
                         'category': category,
                         'filename': fn.replace(".html", ""),
                         'raw_file_name': fn}

            blogs.append(blog_dict)

        categories = Counter(d['category'] for d in blogs)
        templates = {'categories': categories,
                     'blogs': blogs,
                     'file_name_filter': file_name_filter,
                     'category_filter': category_filter}

        assert(len(file_names) == len(set(d['link_name'] for d in blogs)))

        self.render_template('home.html', **templates)

ここに私のベースハンドラーがあります:

class BaseHandler(webapp2.RequestHandler):
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_template(self, filename, **kwargs):
        #kwargs.update({})
        #TODO() datastore caching here for caching of (handlername, handler parameters, changeable parameters, app_upload_date)
        #TODO() write rendered page to its own html file, and just serve that whole file. (includes all posts). JQuery can show/hide posts.
        self.response.write(self.jinja2.render_template(filename, **kwargs))

おそらく、単体テストの実行方法について間違った考えを持っているのでしょうか、それともテストしやすい方法でコードを書くべきだったのでしょうか? または、コードの状態を取得する方法はありますか?

また、誰かがコードを書き直して変数名を変更すると、テストが壊れます。

4

2 に答える 2

6

メソッドをモックBaseHandler.render_templateして、そのパラメーターをテストできます。

人気のある Python モッキング フレームワークのリストについては、この質問を参照してください。

于 2012-05-10T12:51:09.063 に答える
5

proppy の提案のおかげで、モックを使用することになりました。

http://www.voidspace.org.uk/python/mock/

(モックは Python 3 の part または unittest.mock として含まれています)

だからここに私がwebapp2に持っているものに似ている私のmain.pyコードがあります:

BaseHandler.render_template の代わりに BaseHandler.say_yo があることに注意してください

__author__ = 'Robert'

print "hello from main"

class BaseHandler():
    def say_yo(self,some_number=99):
        print "yo"
        return "sup"

class TheHandler(BaseHandler):
    def get(self, my_number=42):
        print "in TheHandler's get()"
        print self.say_yo(my_number)
        return "TheHandler's return string"

およびatest.py :

__author__ = 'Robert'

import unittest
import main
from mock import patch

class DemoTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testNothing(self):
        self.assertEqual(42, 21 + 21)

    def testSomeRequests(self):
        print "hi"
        bh = main.BaseHandler()
        print bh.say_yo()

        print "1111111"

        with patch('main.BaseHandler.say_yo') as patched_bh:
            print dir(patched_bh)
            patched_bh.return_value = 'double_sup'
            bh2 = main.BaseHandler()
            print bh2.say_yo()
            print "222222"

        bh3 = main.BaseHandler()
        print bh3.say_yo()

        print "3333"

        th = main.TheHandler()
        print th.get()

        print "44444"
        with patch('main.BaseHandler.say_yo') as patched_bh:
            patched_bh.return_value = 'last_sup'
            th = main.TheHandler()
            print th.get()
            print th.get(123)
            print "---"
            print patched_bh.called
            print patched_bh.call_args_list
            print "555555"



if __name__ == '__main__':
    unittest.main()

このコードは多くの出力を提供します。サンプルは次のとおりです。

44444
in TheHandler's get()
last_sup
TheHandler's return string
in TheHandler's get()
last_sup
TheHandler's return string
---
True
[call(42), call(123)]
555555
于 2012-05-11T05:39:10.053 に答える