为什么 App Engine 项目不调用 unittest.TestCase.tearDown()?

Why is app engine project not calling unittest.TestCase.tearDown()?

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

正在调用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())  

这是测试的输出:

nosetests -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(),打印的输出被 nosetests 吞没了。
--nocapture 标志停止此行为。

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

似乎保持状态

正在调用 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 测试运行程序调用,显示每个测试的 print 语句的输出:

$ 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)

--nocapture 选项在 http://nose.readthedocs.org/en/latest/plugins/capture.html

中有描述

当前代码与输出不匹配。根据输出,失败的测试是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())  

看起来你执行了不同版本的文件进行测试。