【问题标题】:Why is app engine project not calling unittest.TestCase.tearDown()?为什么应用引擎项目不调用 unittest.TestCase.tearDown()?
【发布时间】:2016-03-21 15:10:13
【问题描述】:

我正在尝试为 App Engine python 教程设置测试。 似乎没有调用 unittest.tearDown() 是因为我在 tearDown 方法中放入的 print 语句没有显示出来。

unittest.TestCase.setUp()被调用了,为什么不调用tearDown()呢?

import sys, os, subprocess, time, unittest, shlex     
sys.path.append("/usr/local/google_appengine")   
sys.path.append('/usr/local/google_appengine/lib/')     
sys.path.append("/usr/local/google_appengine/lib/yaml/lib")      
sys.path.append("/usr/local/google_appengine/lib/webapp2-2.5.2")      
sys.path.append("/usr/local/google_appengine/lib/django-1.5")      
sys.path.append("/usr/local/google_appengine/lib/cherrypy")      
sys.path.append("/usr/local/google_appengine/lib/concurrent")      
sys.path.append("/usr/local/google_appengine/lib/docker")      
sys.path.append("/usr/local/google_appengine/lib/requests")      
sys.path.append("/usr/local/google_appengine/lib/websocket")      
sys.path.append("/usr/local/google_appengine/lib/fancy_urllib")      
sys.path.append("/usr/local/google_appengine/lib/antlr3")      

from selenium import webdriver      
from selenium.webdriver.common.keys import Keys  

from google.appengine.api import memcache, apiproxy_stub, apiproxy_stub_map       
from google.appengine.ext import testbed      
from google.appengine.datastore import datastore_stub_util       
from google.appengine.tools.devappserver2 import devappserver2      
from guestbook import Author, Greeting    
from google.appengine.api import users  
from google.appengine.ext import ndb  


class NewVisitorTest(unittest.TestCase):      
    # enable the datastore stub  
    nosegae_datastore_v3 = True  
    nosegae_datastore_v3_kwargs = {  
        'datastore_file': '/tmp/nosegae.sqlite3',  
        'use_sqlite': True  
    }  

    def setUp(self):      
        self.testbed = testbed.Testbed()  
        self.testbed.setup_env(app_id='guestbook')      
        self.testbed.activate()        
        self.datastore_stub = apiproxy_stub_map.apiproxy.GetStub('datastore_v3')    
        ndb.get_context().clear_cache()    
        APP_CONFIGS = ['app.yaml']      

    def tearDown(self):   
        print("#####################functional_tests.teardown called")  
        self.testbed.deactivate()   
        # I put a print statement into testbed.deactivate and it's not showing up.     
        ndb.get_context().clear_cache()    

    def loginUser(self, email="elonMusk@example.com", id='888', is_admin=False):  
        self.testbed.setup_env(  
            user_email=email,  
            user_id=id,  
            user_is_admin='1' if is_admin else '0',  
            overwrite=True  
        )  
        self.testbed.init_user_stub()  

    def test_guest_can_submit_new_greeting_and_author(self):  

         #self.browser.get('http://localhost:8080')  
         self.loginUser()  
         greetings = Greeting.query(Greeting.author.email=='elonMusk@example.com').get()  
         pprint.pprint(greetings)  
         assert(Greeting.query(Greeting.author.email=='elonMusk@example.com').get()
self.assertEqual(1, len(Greeting.query().fetch(10)))  

    def test_entity_saves(self):  
         self.loginUser()              
         entity_key = Greeting(content="Test Value",   
                           author = Author(  
                                    identity=users.get_current_user().user_id(),  
                                    email=users.get_current_user().email())  
                           ).put()  
         print(entity_key)  
         self.assertIsNotNone(entity_key.id())    
         #self.assertNotNone(entity.key.id())  

这是测试的输出:

鼻子测试 -v --with-gae

test_entity_saves (functional_tests.NewVisitorTest) ... ok  
test_guest_can_submit_new_greeting_and_author (functional_tests.NewVisitorTest) ... FAIL  

======================================================================  
FAIL: test_guest_can_submit_new_greeting_and_author (functional_tests.NewVisitorTest)  
----------------------------------------------------------------------  
Traceback (most recent call last):  
  File "/Users/Bryan/work/GoogleAppEngine/guestbook/functional_tests.py", line 124, in test_guest_can_submit_new_greeting_and_author  
    self.assertEqual(1, len(Greeting.query().fetch(10)))  
AssertionError: 1 != 10  
-------------------- >> begin captured stdout << ---------------------  
#*#**#*#*#*#*#*#*#*#*nosegae.py startTest   
Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))  

--------------------- >> end captured stdout << ----------------------  
-------------------- >> begin captured logging << --------------------  
root: DEBUG: all_pending: add <Future 106a2e690 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); pending>  
root: DEBUG: Clearing stale EventLoop instance...  
root: DEBUG:   current = deque([(<bound method AutoBatcher._finished_callback of AutoBatcher(_memcache_del_tasklet)>, (<Future 1069e9650 created by run_queue(context.py:185) for tasklet _memcache_del_tasklet(context.py:1131); result None>, [(<Future 1069e9590 created by add(context.py:211) for AutoBatcher(_memcache_del_tasklet).add(NDB9:ag1kZXZ-Z3Vlc3Rib29rcg8LEghHcmVldGluZxjhXQw, (0, '', None)); result 1>, 'NDB9:ag1kZXZ-Z3Vlc3Rib29rcg8LEghHcmVldGluZxjhXQw')]), {})])  
root: DEBUG: Cleared  
root: DEBUG: nowevent: _help_tasklet_along  
root: DEBUG: Sending None to initial generator _get_async(query.py:1247)  
root: DEBUG: all_pending: add <Future 106a2e850 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: initial generator _get_async(query.py:1247) yielded <Future 106a2e850 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: <Future 106a2e690 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247) suspended generator _get_async(query.py:1250); pending> is now blocked waiting for <Future 106a2e850 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: nowevent: _help_tasklet_along  
root: DEBUG: Sending None to initial generator _run_to_list(query.py:971)  
root: DEBUG: initial generator _run_to_list(query.py:971) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x106a2ed50>  
root: DEBUG: rpc: datastore_v3.RunQuery  
root: DEBUG: Sending <google.appengine.datastore.datastore_query.Batch object at 0x106a2ec50> to suspended generator _run_to_list(query.py:979)  
root: DEBUG: suspended generator _run_to_list(query.py:979) returned [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]  
root: DEBUG: all_pending: success: remove <Future 106a2e850 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); result [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]>  
root: DEBUG: nowevent: _on_future_completion  
root: DEBUG: <Future 106a2e690 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); pending> is no longer blocked waiting for <Future 106a2e850 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); result [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]>  
root: DEBUG: Sending [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))] to suspended generator _get_async(query.py:1250)  
root: DEBUG: suspended generator _get_async(query.py:1250) returned Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))  
root: DEBUG: all_pending: success: remove <Future 106a2e690 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); result Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))>  
root: DEBUG: all_pending: add <Future 1069e9ad0 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); pending>  
root: DEBUG: nowevent: _help_tasklet_along  
root: DEBUG: Sending None to initial generator _get_async(query.py:1247)  
root: DEBUG: all_pending: add <Future 106a2e650 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: initial generator _get_async(query.py:1247) yielded <Future 106a2e650 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: <Future 1069e9ad0 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247) suspended generator _get_async(query.py:1250); pending> is now blocked waiting for <Future 106a2e650 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: nowevent: _help_tasklet_along  
root: DEBUG: Sending None to initial generator _run_to_list(query.py:971)  
root: DEBUG: initial generator _run_to_list(query.py:971) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x106a2ee50>  
root: DEBUG: rpc: datastore_v3.RunQuery  
root: DEBUG: Sending <google.appengine.datastore.datastore_query.Batch object at 0x106a2ee10> to suspended generator _run_to_list(query.py:979)  
root: DEBUG: suspended generator _run_to_list(query.py:979) returned [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]  
root: DEBUG: all_pending: success: remove <Future 106a2e650 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); result [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]>  
root: DEBUG: nowevent: _on_future_completion  
root: DEBUG: <Future 1069e9ad0 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); pending> is no longer blocked waiting for <Future 106a2e650 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); result [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))]>  
root: DEBUG: Sending [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))] to suspended generator _get_async(query.py:1250)  
root: DEBUG: suspended generator _get_async(query.py:1250) returned Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))  
root: DEBUG: all_pending: success: remove <Future 1069e9ad0 created by get_async(query.py:1245) for tasklet _get_async(query.py:1247); result Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460))>  
root: DEBUG: all_pending: add <Future 1069cf8d0 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); pending>  
root: DEBUG: nowevent: _help_tasklet_along  
root: DEBUG: Sending None to initial generator _run_to_list(query.py:971)  
root: DEBUG: initial generator _run_to_list(query.py:971) yielded <google.appengine.api.apiproxy_stub_map.UserRPC object at 0x106a2edd0>  
root: DEBUG: rpc: datastore_v3.RunQuery  
root: DEBUG: Sending <google.appengine.datastore.datastore_query.Batch object at 0x106a2ef10> to suspended generator _run_to_list(query.py:979)  
root: DEBUG: suspended generator _run_to_list(query.py:979) returned [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460)), Greeting(key=Key('Greeting', 1001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 43, 164283)), Greeting(key=Key('Greeting', 2001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 44, 59, 425351)), Greeting(key=Key('Greeting', 3001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 45, 39, 127541)), Greeting(key=Key('Greeting', 4001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 46, 40, 884853)), Greeting(key=Key('Greeting', 5001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 21, 10, 45, 14308)), Greeting(key=Key('Greeting', 6001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 21, 56, 12, 419565)), Greeting(key=Key('Greeting', 7001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 22, 0, 14, 800335)), Greeting(key=Key('Greeting', 8001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 22, 1, 7, 931768)), Greeting(key=Key('Greeting', 9001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 21, 13, 34, 43, 876008))]  
root: DEBUG: all_pending: success: remove <Future 1069cf8d0 created by fetch_async(query.py:1223) for tasklet _run_to_list(query.py:971); result [Greeting(key=Key('Greeting', 1), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 37, 659460)), Greeting(key=Key('Greeting', 1001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 39, 43, 164283)), Greeting(key=Key('Greeting', 2001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 44, 59, 425351)), Greeting(key=Key('Greeting', 3001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 45, 39, 127541)), Greeting(key=Key('Greeting', 4001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 20, 46, 40, 884853)), Greeting(key=Key('Greeting', 5001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 21, 10, 45, 14308)), Greeting(key=Key('Greeting', 6001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 21, 56, 12, 419565)), Greeting(key=Key('Greeting', 7001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 22, 0, 14, 800335)), Greeting(key=Key('Greeting', 8001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 18, 22, 1, 7, 931768)), Greeting(key=Key('Greeting', 9001), author=Author(email=u'elonMusk@example.com', identity=u'888'), content=u'Test Value', date=datetime.datetime(2016, 3, 21, 13, 34, 43, 876008))]>  
--------------------- >> end captured logging << ---------------------  

----------------------------------------------------------------------  
Ran 2 tests in 0.835s  

FAILED (failures=1)  
#

编辑解决方案:
调用了 teardown() ,打印的输出被鼻子测试吞没了。
--nocapture 标志会阻止这种行为。

数据存储实体在失败测试中的持久性源于 testbed.deactivate() 似乎只刷新内存中的数据存储,而不是存储在硬盘驱动器文件中的数据。
我已经用 sqlite3 数据库的路径定义了“datastore_file”,尽管 testbed.deactivate()

【问题讨论】:

  • 设置中有没有异常?仅当设置成功时才调用拆卸
  • 我已经寻找了例外。如果它们正在发生,它们不会被记录,因为我包含了上面的所有输出。我也尝试在设置中放置打印语句并记录它们,所以我认为设置运行没有问题。我怎样才能变得更细化?
  • 您的测试在test_guest_can_submit_new_greeting_and_author 失败,对吧?我已经有一段时间没有进行 Python 测试了,但是如果在退出类之前测试失败,会调用 tearDown 作为类级别的方法吗?
  • 您能否尝试将文件写入文件作为 tearDown() 方法的一部分,并让我们知道这是否有效? (将有助于区分未出现的预期打印输出和未调用 tearDown())
  • 除了print语句,你怎么知道tearDown没有被调用?

标签: python google-app-engine python-unittest


【解决方案1】:

tearDown 方法正在被调用,但 nosetests 正在吞噬输出。

这是一个最小的例子。

import unittest


class MyTestCase(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        print 'Calling tearDown'

    def test_1(self):
        self.assertTrue(True)

    def test_2(self):
        self.assertTrue(False)

使用标准库 unittest 测试运行程序调用,打印语句的输出显示为每个测试:

$ python -m unittest tests
Calling tearDown
.FCalling tearDown

======================================================================
FAIL: test_2 (tests.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 16, in test_2
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

用nosetests调用,输出不显示:

$ nosetests -v  --with-gae --gae-lib-root=$APPENGINE
test_1 (tests.MyTestCase) ... ok
test_2 (tests.MyTestCase) ... FAIL

======================================================================
FAIL: test_2 (tests.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/kev/python_projects/usr/local/bin/python2.7/tests.py", line 16, in test_2
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.268s

FAILED (failures=1)

如果我们将 --nocapture 标志传递给nosetests,打印语句的输出就会显示出来:

$ nosetests -v --nocapture --with-gae --gae-lib-root=$APPENGINE
test_1 (tests.MyTestCase) ... Calling tearDown
ok
test_2 (tests.MyTestCase) ... FAIL
Calling tearDown

======================================================================
FAIL: test_2 (tests.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/kev/python_projects/usr/local/bin/python2.7/tests.py", line 16, in test_2
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.265s

FAILED (failures=1)

http://nose.readthedocs.org/en/latest/plugins/capture.html 中描述了 --nocapture 选项

【讨论】:

  • --no-capture 确实显示了之前隐藏的打印语句。看起来像是调用了 teardown() ,但无论出于何种原因都没有刷新数据库。
  • @BryanWheelock 我不能肯定地说,但看起来您的代码是 GAE 文档中描述的“unittest”测试方法和 Nosegae 文档中描述的混合体,其中没有调用 setUp/tearDown。如果您想坚持使用鼻子,我建议您查看pythonhosted.org/NoseGAE/#configuring-the-testbed 并更密切地关注他们的示例代码。
  • 感谢您的链接。我很难在文档cloud.google.com/appengine/docs 之外找到任何示例代码
【解决方案2】:

存在的代码与输出不匹配。根据输出,失败的测试是test_guest_can_submit_new_greeting_and_author,失败如下:

Traceback (most recent call last):  
      File "/Users/Bryan/work/GoogleAppEngine/guestbook/functional_tests.py", line 124, in test_guest_can_submit_new_greeting_and_author  
        self.assertEqual(1, len(Greeting.query().fetch(10)))  
    AssertionError: 1 != 10 

但 test_guest_can_submit_new_greeting_and_author 不包含显示的断言:

def test_guest_can_submit_new_greeting_and_author(self):  

     #self.browser.get('http://localhost:8080')  
     self.loginUser()  
     greetings = Greeting.query(Greeting.author.email=='elonMusk@example.com').get()  
     pprint.pprint(greetings)  
     assert(Greeting.query(Greeting.author.email=='elonMusk@example.com').get())  

看起来您使用测试执行了不同版本的文件。

【讨论】:

  • 好眼光。我的代码中有一堆我删除的 cmets,我不小心删除了:self.assertEqual(1, len(Greeting.query().fetch(10)))
猜你喜欢
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 2014-07-31
  • 1970-01-01
  • 2013-03-28
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多