diff --git a/appengine/app_identity/signing/main_test.py b/appengine/app_identity/signing/main_test.py index 18a1ed4fc4b..2c2fdbc7bc8 100644 --- a/appengine/app_identity/signing/main_test.py +++ b/appengine/app_identity/signing/main_test.py @@ -13,17 +13,11 @@ # limitations under the License. import main -from testing import AppEngineTest import webtest -class TestAppIdentityHandler(AppEngineTest): - def setUp(self): - super(TestAppIdentityHandler, self).setUp() - - self.app = webtest.TestApp(main.app) - - def test_get(self): - response = self.app.get('/') - self.assertEqual(response.status_int, 200) - self.assertTrue('Verified: True' in response.text) +def test_app(testbed): + app = webtest.TestApp(main.app) + response = app.get('/') + assert response.status_int == 200 + assert 'Verified: True' in response.text diff --git a/appengine/bigquery/main_test.py b/appengine/bigquery/main_test.py index 31405bd19ec..4d22d67d243 100644 --- a/appengine/bigquery/main_test.py +++ b/appengine/bigquery/main_test.py @@ -17,47 +17,48 @@ from apiclient.http import HttpMock import main import mock -import testing +import pytest import webtest -class TestAuthSample(testing.AppEngineTest): +@pytest.fixture +def app(cloud_config, testbed): + main.PROJECTID = cloud_config.GCLOUD_PROJECT + return webtest.TestApp(main.app) - def setUp(self): - super(TestAuthSample, self).setUp() - self.app = webtest.TestApp(main.app) - main.PROJECTID = self.config.GCLOUD_PROJECT - def test_anonymous_get(self): - response = self.app.get('/') +def test_anonymous(app): + response = app.get('/') - # Should redirect to login - self.assertEqual(response.status_int, 302) - self.assertRegexpMatches(response.headers['Location'], - r'.*accounts.*Login.*') + # Should redirect to login + assert response.status_int == 302 + assert re.search(r'.*accounts.*Login.*', response.headers['Location']) - def test_loggedin_get(self): - self.login_user() - response = self.app.get('/') +def test_loggedin(app, login): + login() - # Should redirect to login - self.assertEqual(response.status_int, 302) - self.assertRegexpMatches(response.headers['Location'], r'.*oauth2.*') + response = app.get('/') - @mock.patch.object(main.decorator, 'has_credentials', return_value=True) - def test_oauthed_get(self, *args): - self.login_user() + # Should redirect to oauth2 + assert response.status_int == 302 + assert re.search(r'.*oauth2.*', response.headers['Location']) - mock_http = HttpMock( - self.resource_path('datasets-list.json'), - {'status': '200'}) - with mock.patch.object(main.decorator, 'http', return_value=mock_http): - response = self.app.get('/') +def test_oauthed(resource, app, login): + login() - # Should make the api call - self.assertEqual(response.status_int, 200) - self.assertRegexpMatches( - response.body, - re.compile(r'.*datasets.*datasetReference.*etag.*', re.DOTALL)) + mock_http = HttpMock( + resource('datasets-list.json'), + {'status': '200'}) + + with mock.patch.object(main.decorator, 'http', return_value=mock_http): + with mock.patch.object( + main.decorator, 'has_credentials', return_value=True): + response = app.get('/') + + # Should make the api call + assert response.status_int == 200 + assert re.search( + re.compile(r'.*datasets.*datasetReference.*etag.*', re.DOTALL), + response.body) diff --git a/appengine/blobstore/main_test.py b/appengine/blobstore/main_test.py index ead93e06123..2b62074dae4 100644 --- a/appengine/blobstore/main_test.py +++ b/appengine/blobstore/main_test.py @@ -13,18 +13,13 @@ # limitations under the License. import main -import testing import webtest -class TestBlobstoreSample(testing.AppEngineTest): +def test_app(testbed, login): + app = webtest.TestApp(main.app) - def setUp(self): - super(TestBlobstoreSample, self).setUp() - self.app = webtest.TestApp(main.app) + login() + response = app.get('/') - def test_form(self): - self.login_user() - response = self.app.get('/') - - self.assertTrue('/_ah/upload' in response) + assert '/_ah/upload' in response diff --git a/appengine/cloudsql/main_test.py b/appengine/cloudsql/main_test.py index 771351e6881..f2debea7a96 100644 --- a/appengine/cloudsql/main_test.py +++ b/appengine/cloudsql/main_test.py @@ -14,24 +14,20 @@ import os import re -from unittest.case import SkipTest import main -import testing +import pytest import webtest -class TestMySQLSample(testing.AppEngineTest): +@pytest.mark.skipif( + not os.path.exists('/var/run/mysqld/mysqld.sock'), + reason='MySQL server not available.') +def test_app(): + app = webtest.TestApp(main.app) + response = app.get('/') - def setUp(self): - if not os.path.exists('/var/run/mysqld/mysqld.sock'): - raise SkipTest('No MySQL server found.') - super(TestMySQLSample, self).setUp() - self.app = webtest.TestApp(main.app) - - def test_get(self): - response = self.app.get('/') - self.assertEqual(response.status_int, 200) - self.assertRegexpMatches( - response.body, - re.compile(r'.*version.*', re.DOTALL)) + assert response.status_int == 200 + assert re.search( + re.compile(r'.*version.*', re.DOTALL), + response.body) diff --git a/appengine/conftest.py b/appengine/conftest.py index fa252fd1f58..ff92c6fc95e 100644 --- a/appengine/conftest.py +++ b/appengine/conftest.py @@ -1,3 +1,4 @@ +import pytest import testing.appengine @@ -7,3 +8,28 @@ def pytest_configure(config): def pytest_runtest_call(item): testing.appengine.import_appengine_config() + + +@pytest.yield_fixture +def testbed(): + testbed = testing.appengine.setup_testbed() + yield testbed + testbed.deactivate() + + +@pytest.fixture +def login(testbed): + def _login(email='user@example.com', id='123', is_admin=False): + testbed.setup_env( + user_email=email, + user_id=id, + user_is_admin='1' if is_admin else '0', + overwrite=True) + return _login + + +@pytest.fixture +def run_tasks(testbed): + def _run_tasks(app): + testing.appengine.run_tasks(testbed, app) + return _run_tasks diff --git a/appengine/images/main_test.py b/appengine/images/main_test.py index 0b14c8f7854..f3315973587 100644 --- a/appengine/images/main_test.py +++ b/appengine/images/main_test.py @@ -14,60 +14,64 @@ import main import mock -from testing import AppEngineTest +import pytest import webtest -class TestHandlers(AppEngineTest): - def setUp(self): - super(TestHandlers, self).setUp() - self.app = webtest.TestApp(main.app) +@pytest.fixture +def app(testbed): + return webtest.TestApp(main.app) - def test_get(self): - main.Greeting( - parent=main.guestbook_key('default_guestbook'), - author='123', - content='abc' - ).put() - response = self.app.get('/') +def test_get(app): + main.Greeting( + parent=main.guestbook_key('default_guestbook'), + author='123', + content='abc' + ).put() - # Let's check if the response is correct. - self.assertEqual(response.status_int, 200) + response = app.get('/') - @mock.patch('main.images') - def test_post(self, mock_images): + # Let's check if the response is correct. + assert response.status_int == 200 + + +def test_post(app): + with mock.patch('main.images') as mock_images: mock_images.resize.return_value = 'asdf' - response = self.app.post('/sign', {'content': 'asdf'}) + response = app.post('/sign', {'content': 'asdf'}) mock_images.resize.assert_called_once_with(mock.ANY, 32, 32) # Correct response is a redirect - self.assertEqual(response.status_int, 302) + assert response.status_int == 302 + + +def test_img(app): + greeting = main.Greeting( + parent=main.guestbook_key('default_guestbook'), + id=123 + ) + greeting.author = 'asdf' + greeting.content = 'asdf' + greeting.avatar = b'123' + greeting.put() + + response = app.get('/img?img_id=%s' % greeting.key.urlsafe()) - def test_img(self): - greeting = main.Greeting( - parent=main.guestbook_key('default_guestbook'), - id=123 - ) - greeting.author = 'asdf' - greeting.content = 'asdf' - greeting.avatar = b'123' - greeting.put() + assert response.status_int == 200 - response = self.app.get('/img?img_id=%s' % greeting.key.urlsafe()) - self.assertEqual(response.status_int, 200) +def test_img_missing(app): + # Bogus image id, should get error + app.get('/img?img_id=123', status=500) - def test_img_missing(self): - # Bogus image id, should get error - self.app.get('/img?img_id=123', status=500) - @mock.patch('main.images') - def test_post_and_get(self, mock_images): +def test_post_and_get(app): + with mock.patch('main.images') as mock_images: mock_images.resize.return_value = 'asdf' - self.app.post('/sign', {'content': 'asdf'}) - response = self.app.get('/') + app.post('/sign', {'content': 'asdf'}) + response = app.get('/') - self.assertEqual(response.status_int, 200) + assert response.status_int == 200 diff --git a/appengine/logging/reading_logs/main_test.py b/appengine/logging/reading_logs/main_test.py index 51dc1234eab..439243f7b35 100644 --- a/appengine/logging/reading_logs/main_test.py +++ b/appengine/logging/reading_logs/main_test.py @@ -13,18 +13,12 @@ # limitations under the License. import main -from testing import AppEngineTest import webtest -class TestReadingLogs(AppEngineTest): - def setUp(self): - super(TestReadingLogs, self).setUp() - - self.app = webtest.TestApp(main.app) - - def test_get(self): - response = self.app.get('/') - self.assertEqual(response.status_int, 200) - self.assertTrue('No log entries found' in response.text) - self.assertTrue('More' not in response.text) +def test_app(testbed): + app = webtest.TestApp(main.app) + response = app.get('/') + assert response.status_int == 200 + assert 'No log entries found' in response.text + assert 'More' not in response.text diff --git a/appengine/logging/writing_logs/main_test.py b/appengine/logging/writing_logs/main_test.py index b6b27fb7019..3f0f38b1ee8 100644 --- a/appengine/logging/writing_logs/main_test.py +++ b/appengine/logging/writing_logs/main_test.py @@ -13,17 +13,11 @@ # limitations under the License. import main -from testing import AppEngineTest import webtest -class TestWritingLogs(AppEngineTest): - def setUp(self): - super(TestWritingLogs, self).setUp() - - self.app = webtest.TestApp(main.app) - - def test_get(self): - response = self.app.get('/') - self.assertEqual(response.status_int, 200) - self.assertTrue('Logging example' in response.text) +def test_app(testbed): + app = webtest.TestApp(main.app) + response = app.get('/') + assert response.status_int == 200 + assert 'Logging example' in response.text diff --git a/appengine/mailgun/main_test.py b/appengine/mailgun/main_test.py index 1c47c7aabad..8270716b84f 100644 --- a/appengine/mailgun/main_test.py +++ b/appengine/mailgun/main_test.py @@ -13,42 +13,43 @@ # limitations under the License. import main -from testing import AppEngineTest, Http2Mock +import pytest +from testing import Http2Mock import webtest -class TestMailgunHandlers(AppEngineTest): - def setUp(self): - super(TestMailgunHandlers, self).setUp() +@pytest.fixture +def app(): + return webtest.TestApp(main.app) - self.app = webtest.TestApp(main.app) - def test_get(self): - response = self.app.get('/') - self.assertEqual(response.status_int, 200) +def test_get(app): + response = app.get('/') + assert response.status_int == 200 - def test_post(self): - http = Http2Mock(responses=[{}]) - with http: - response = self.app.post('/', { - 'recipient': 'jonwayne@google.com', - 'submit': 'Send simple email'}) +def test_post(app): + http = Http2Mock(responses=[{}]) - self.assertEqual(response.status_int, 200) + with http: + response = app.post('/', { + 'recipient': 'jonwayne@google.com', + 'submit': 'Send simple email'}) - http = Http2Mock(responses=[{}]) + assert response.status_int == 200 - with http: - response = self.app.post('/', { - 'recipient': 'jonwayne@google.com', - 'submit': 'Send complex email'}) + http = Http2Mock(responses=[{}]) - self.assertEqual(response.status_int, 200) + with http: + response = app.post('/', { + 'recipient': 'jonwayne@google.com', + 'submit': 'Send complex email'}) - http = Http2Mock(responses=[{'status': 500, 'body': 'Test error'}]) + assert response.status_int == 200 - with http, self.assertRaises(Exception): - self.app.post('/', { - 'recipient': 'jonwayne@google.com', - 'submit': 'Send simple email'}) + http = Http2Mock(responses=[{'status': 500, 'body': 'Test error'}]) + + with http, pytest.raises(Exception): + app.post('/', { + 'recipient': 'jonwayne@google.com', + 'submit': 'Send simple email'}) diff --git a/appengine/memcache/guestbook/main_test.py b/appengine/memcache/guestbook/main_test.py index 7c70b65bf28..977004c1abe 100644 --- a/appengine/memcache/guestbook/main_test.py +++ b/appengine/memcache/guestbook/main_test.py @@ -14,15 +14,10 @@ import main -from testing import AppEngineTest import webtest -class TestHandlers(AppEngineTest): - - def test_hello(self): - app = webtest.TestApp(main.app) - response = app.get('/') - - # Let's check if the response is correct. - self.assertEqual(response.status_int, 200) +def test_app(testbed): + app = webtest.TestApp(main.app) + response = app.get('/') + assert response.status_int == 200 diff --git a/appengine/multitenancy/datastore_test.py b/appengine/multitenancy/datastore_test.py index e82f59ebf91..3c3dcc2f284 100644 --- a/appengine/multitenancy/datastore_test.py +++ b/appengine/multitenancy/datastore_test.py @@ -13,27 +13,22 @@ # limitations under the License. import datastore -import testing import webtest -class TestNamespaceDatastoreSample(testing.AppEngineTest): +def test_datastore(testbed): + app = webtest.TestApp(datastore.app) - def setUp(self): - super(TestNamespaceDatastoreSample, self).setUp() - self.app = webtest.TestApp(datastore.app) + response = app.get('/datastore') + assert response.status_int == 200 + assert 'Global: 1' in response.body - def test_get(self): - response = self.app.get('/datastore') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 1' in response.body) + response = app.get('/datastore/a') + assert response.status_int == 200 + assert 'Global: 2' in response.body + assert 'a: 1' in response.body - response = self.app.get('/datastore/a') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 2' in response.body) - self.assertTrue('a: 1' in response.body) - - response = self.app.get('/datastore/b') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 3' in response.body) - self.assertTrue('b: 1' in response.body) + response = app.get('/datastore/b') + assert response.status_int == 200 + assert 'Global: 3' in response.body + assert 'b: 1' in response.body diff --git a/appengine/multitenancy/memcache_test.py b/appengine/multitenancy/memcache_test.py index 305e3c851af..97bc7504e17 100644 --- a/appengine/multitenancy/memcache_test.py +++ b/appengine/multitenancy/memcache_test.py @@ -13,27 +13,22 @@ # limitations under the License. import memcache -import testing import webtest -class TestNamespaceMemcacheSample(testing.AppEngineTest): +def test_memcache(testbed): + app = webtest.TestApp(memcache.app) - def setUp(self): - super(TestNamespaceMemcacheSample, self).setUp() - self.app = webtest.TestApp(memcache.app) + response = app.get('/memcache') + assert response.status_int == 200 + assert 'Global: 1' in response.body - def test_get(self): - response = self.app.get('/memcache') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 1' in response.body) + response = app.get('/memcache/a') + assert response.status_int == 200 + assert 'Global: 2' in response.body + assert 'a: 1' in response.body - response = self.app.get('/memcache/a') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 2' in response.body) - self.assertTrue('a: 1' in response.body) - - response = self.app.get('/memcache/b') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 3' in response.body) - self.assertTrue('b: 1' in response.body) + response = app.get('/memcache/b') + assert response.status_int == 200 + assert 'Global: 3' in response.body + assert 'b: 1' in response.body diff --git a/appengine/multitenancy/taskqueue_test.py b/appengine/multitenancy/taskqueue_test.py index 9f4d12da9ef..c0f658bc2ac 100644 --- a/appengine/multitenancy/taskqueue_test.py +++ b/appengine/multitenancy/taskqueue_test.py @@ -13,33 +13,28 @@ # limitations under the License. import taskqueue -import testing import webtest -class TestNamespaceTaskQueueSample(testing.AppEngineTest): +def test_taskqueue(testbed, run_tasks): + app = webtest.TestApp(taskqueue.app) - def setUp(self): - super(TestNamespaceTaskQueueSample, self).setUp() - self.app = webtest.TestApp(taskqueue.app) + response = app.get('/taskqueue') + assert response.status_int == 200 + assert 'Global: 0' in response.body - def test_get(self): - response = self.app.get('/taskqueue') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 0' in response.body) + run_tasks(app) - self.run_tasks() + response = app.get('/taskqueue') + assert response.status_int == 200 + assert 'Global: 1' in response.body - response = self.app.get('/taskqueue') - self.assertEqual(response.status_int, 200) - self.assertTrue('Global: 1' in response.body) + response = app.get('/taskqueue/a') + assert response.status_int == 200 + assert 'a: 0' in response.body - response = self.app.get('/taskqueue/a') - self.assertEqual(response.status_int, 200) - self.assertTrue('a: 0' in response.body) + run_tasks(app) - self.run_tasks() - - response = self.app.get('/taskqueue/a') - self.assertEqual(response.status_int, 200) - self.assertTrue('a: 1' in response.body) + response = app.get('/taskqueue/a') + assert response.status_int == 200 + assert 'a: 1' in response.body diff --git a/appengine/ndb/modeling/contact_with_group_models_test.py b/appengine/ndb/modeling/contact_with_group_models_test.py index 0b0f694c961..0ec40949d1c 100644 --- a/appengine/ndb/modeling/contact_with_group_models_test.py +++ b/appengine/ndb/modeling/contact_with_group_models_test.py @@ -12,43 +12,34 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Test classes for code snippet for modeling article.""" - import contact_with_group_models as models from google.appengine.ext import ndb -from testing import AppEngineTest - -class ContactTestCase(AppEngineTest): - """A test case for the Contact model with groups.""" - def setUp(self): - """Creates 3 contacts and 1 group. - Assuming the group and contacts are private and belong to tmatsuo's - addressbook. - """ - super(ContactTestCase, self).setUp() - self.myaddressbook_key = ndb.Key('AddressBook', 'tmatsuo') - - friends = models.Group(parent=self.myaddressbook_key, name='friends') - friends.put() - self.friends_key = friends.key - mary = models.Contact(parent=self.myaddressbook_key, name='Mary') +def test_models(testbed): + # Creates 3 contacts and 1 group. + # Assuming the group and contacts are private and belong to tmatsuo's + # addressbook. + addressbook_key = ndb.Key('AddressBook', 'tmatsuo') + + friends = models.Group(parent=addressbook_key, name='friends') + friends.put() + friends_key = friends.key + mary = models.Contact(parent=addressbook_key, name='Mary') + mary.put() + mary_key = mary.key + + # Add Mary to your 'friends' group + mary = mary_key.get() + friends = friends_key.get() + if friends.key not in mary.groups: + mary.groups.append(friends.key) mary.put() - self.mary_key = mary.key - - def test_groups(self): - # Add Mary to your 'friends' group - mary = self.mary_key.get() - friends = self.friends_key.get() - if friends.key not in mary.groups: - mary.groups.append(friends.key) - mary.put() - # Now Mary is your friend - mary = self.mary_key.get() - self.assertTrue(friends.key in mary.groups) + # Now Mary is your friend + mary = mary_key.get() + assert friends.key in mary.groups - # How about 'members' property? - friend_list = friends.members.fetch() - self.assertEqual(len(friend_list), 1) + # How about 'members' property? + friend_list = friends.members.fetch() + assert len(friend_list) == 1 diff --git a/appengine/ndb/modeling/keyproperty_models_test.py b/appengine/ndb/modeling/keyproperty_models_test.py index fa54b3d211b..66c983ac4d5 100644 --- a/appengine/ndb/modeling/keyproperty_models_test.py +++ b/appengine/ndb/modeling/keyproperty_models_test.py @@ -14,37 +14,31 @@ """Test classes for code snippet for modeling article.""" -import unittest - import keyproperty_models as models -from testing import AppEngineTest - - -class ContactTestCase(AppEngineTest): - """A test case for the Contact model class with KeyProperty.""" - NAME = 'Takashi Matsuo' - - def setUp(self): - super(ContactTestCase, self).setUp() - contact = models.Contact(name=self.NAME) - contact.put() - self.contact_key = contact.key - - def test_basic(self): - """Test for getting a Contact entity.""" - contact = self.contact_key.get() - self.assertEqual(contact.name, self.NAME) - - # This test fails because of the eventual consistency nature of - # HRD. We configure HRD consistency for the test datastore stub to - # match the production behavior. - @unittest.skip("Intentionally showing a failing test case.") - # [START failing_test] - def test_fails(self): - contact = self.contact_key.get() - models.PhoneNumber(contact=self.contact_key, - phone_type='home', - number='(650) 555 - 2200').put() - numbers = contact.phone_numbers.fetch() - self.assertEqual(1, len(numbers)) - # [END failing_test] +import pytest + + +def test_models(testbed): + name = 'Takashi Matsuo' + contact = models.Contact(name=name) + contact.put() + contact = contact.key.get() + assert contact.name == name + + +# This test fails because of the eventual consistency nature of +# HRD. We configure HRD consistency for the test datastore stub to +# match the production behavior. +@pytest.mark.xfail +# [START failing_test] +def test_fails(self): + contact = models.Contact(name='Example') + contact.put() + + models.PhoneNumber( + contact=self.contact_key, + phone_type='home', + number='(650) 555 - 2200').put() + numbers = contact.phone_numbers.fetch() + assert 1 == len(numbers) +# [END failing_test] diff --git a/appengine/ndb/modeling/naive_models_test.py b/appengine/ndb/modeling/naive_models_test.py index 360c88f55f8..7b6414673e3 100644 --- a/appengine/ndb/modeling/naive_models_test.py +++ b/appengine/ndb/modeling/naive_models_test.py @@ -15,20 +15,11 @@ """Test classes for code snippet for modeling article.""" import naive_models as models -from testing import AppEngineTest -class ContactTestCase(AppEngineTest): - """A test case for the naive Contact model classe.""" - NAME = 'Takashi Matsuo' - - def setUp(self): - super(ContactTestCase, self).setUp() - contact = models.Contact(name=self.NAME) - contact.put() - self.contact_key = contact.key - - def test_basic(self): - """Test for getting a NaiveContact entity.""" - contact = self.contact_key.get() - self.assertEqual(contact.name, self.NAME) +def test_models(testbed): + name = 'Takashi Matsuo' + contact = models.Contact(name=name) + contact.put() + contact = contact.key.get() + assert contact.name == name diff --git a/appengine/ndb/modeling/parent_child_models_test.py b/appengine/ndb/modeling/parent_child_models_test.py index f10673a63ca..cae2c6bedc7 100644 --- a/appengine/ndb/modeling/parent_child_models_test.py +++ b/appengine/ndb/modeling/parent_child_models_test.py @@ -16,65 +16,66 @@ from google.appengine.ext import ndb import parent_child_models as models -from testing import AppEngineTest +import pytest -class ContactTestCase(AppEngineTest): - """A test case for the Contact model class with KeyProperty.""" - NAME = 'Takashi Matsuo' +NAME = 'Takashi Matsuo' - def setUp(self): - super(ContactTestCase, self).setUp() - contact = models.Contact(name=self.NAME) - contact.put() - self.contact_key = contact.key - def test_basic(self): - """Test for getting a Contact entity.""" - contact = self.contact_key.get() - self.assertEqual(contact.name, self.NAME) +@pytest.fixture +def contact_key(testbed): + contact = models.Contact(name=NAME) + contact.put() + return contact.key - # [START succeeding_test] - def test_success(self): - contact = self.contact_key.get() - models.PhoneNumber(parent=self.contact_key, - phone_type='home', - number='(650) 555 - 2200').put() - numbers = contact.phone_numbers.fetch() - self.assertEqual(1, len(numbers)) - # [START succeeding_test] - def test_phone_numbers(self): - """A test for 'phone_numbers' property.""" - models.PhoneNumber(parent=self.contact_key, - phone_type='home', - number='(650) 555 - 2200').put() - models.PhoneNumber(parent=self.contact_key, - phone_type='mobile', - number='(650) 555 - 2201').put() - contact = self.contact_key.get() - for phone in contact.phone_numbers: - # it doesn't ensure any order - if phone.phone_type == 'home': - self.assertEqual('(650) 555 - 2200', phone.number) - elif phone.phone_type == 'mobile': - self.assertEqual(phone.number, '(650) 555 - 2201') +def test_basic(contact_key): + contact = contact_key.get() + assert contact.name == NAME - # filer the phone numbers by type. Note that this is an - # ancestor query. - query = contact.phone_numbers.filter( - models.PhoneNumber.phone_type == 'home') - entities = query.fetch() - self.assertEqual(1, len(entities)) - self.assertEqual(entities[0].number, '(650) 555 - 2200') - # delete the mobile phones - query = contact.phone_numbers.filter( - models.PhoneNumber.phone_type == 'mobile') - ndb.delete_multi([e.key for e in query]) +# [START succeeding_test] +def test_success(contact_key): + contact = contact_key.get() + models.PhoneNumber(parent=contact_key, + phone_type='home', + number='(650) 555 - 2200').put() + numbers = contact.phone_numbers.fetch() + assert 1 == len(numbers) +# [START succeeding_test] - # make sure there's no mobile phones any more - query = contact.phone_numbers.filter( - models.PhoneNumber.phone_type == 'mobile') - entities = query.fetch() - self.assertEqual(0, len(entities)) + +def test_phone_numbers(contact_key): + """A test for 'phone_numbers' property.""" + models.PhoneNumber(parent=contact_key, + phone_type='home', + number='(650) 555 - 2200').put() + models.PhoneNumber(parent=contact_key, + phone_type='mobile', + number='(650) 555 - 2201').put() + contact = contact_key.get() + for phone in contact.phone_numbers: + # it doesn't ensure any order + if phone.phone_type == 'home': + assert '(650) 555 - 2200' == phone.number + elif phone.phone_type == 'mobile': + assert phone.number == '(650) 555 - 2201' + + # filer the phone numbers by type. Note that this is an + # ancestor query. + query = contact.phone_numbers.filter( + models.PhoneNumber.phone_type == 'home') + entities = query.fetch() + assert 1 == len(entities) + assert entities[0].number == '(650) 555 - 2200' + + # delete the mobile phones + query = contact.phone_numbers.filter( + models.PhoneNumber.phone_type == 'mobile') + ndb.delete_multi([e.key for e in query]) + + # make sure there's no mobile phones any more + query = contact.phone_numbers.filter( + models.PhoneNumber.phone_type == 'mobile') + entities = query.fetch() + assert 0 == len(entities) diff --git a/appengine/ndb/modeling/relation_model_models_test.py b/appengine/ndb/modeling/relation_model_models_test.py index d954d96d5ed..14d4359a298 100644 --- a/appengine/ndb/modeling/relation_model_models_test.py +++ b/appengine/ndb/modeling/relation_model_models_test.py @@ -16,42 +16,28 @@ from google.appengine.ext import ndb import relation_model_models as models -from testing import AppEngineTest -class ContactTestCase(AppEngineTest): - """A test case for the Contact model with relationship model.""" - def setUp(self): - """Creates 1 contact and 1 company. +def test_relationship(testbed): + # Creates 1 contact and 2 companies + addressbook_key = ndb.Key('AddressBook', 'tmatsuo') + mary = models.Contact(parent=addressbook_key, name='Mary') + mary.put() + google = models.Company(name='Google') + google.put() + candit = models.Company(name='Candit') + candit.put() - Assuming the contact belongs to tmatsuo's addressbook. - """ - super(ContactTestCase, self).setUp() - self.myaddressbook_key = ndb.Key('AddressBook', 'tmatsuo') - mary = models.Contact(parent=self.myaddressbook_key, name='Mary') - mary.put() - self.mary_key = mary.key - google = models.Company(name='Google') - google.put() - self.google_key = google.key - candit = models.Company(name='Candit') - candit.put() - self.candit_key = candit.key + # first google hires Mary + models.ContactCompany(parent=addressbook_key, + contact=mary.key, + company=google.key, + title='engineer').put() + # then another company named 'candit' hires Mary too + models.ContactCompany(parent=addressbook_key, + contact=mary.key, + company=candit.key, + title='president').put() - def test_relationship(self): - """Two companies hire Mary.""" - mary = self.mary_key.get() - google = self.google_key.get() - candit = self.candit_key.get() - # first google hires Mary - models.ContactCompany(parent=self.myaddressbook_key, - contact=mary.key, - company=google.key, - title='engineer').put() - # then another company named 'candit' hires Mary too - models.ContactCompany(parent=self.myaddressbook_key, - contact=mary.key, - company=candit.key, - title='president').put() - # get the list of companies that Mary belongs to - self.assertEqual(len(mary.companies), 2) + # get the list of companies that Mary belongs to + assert len(mary.companies) == 2 diff --git a/appengine/ndb/modeling/structured_property_models_test.py b/appengine/ndb/modeling/structured_property_models_test.py index 11e5e47d627..41f5e5bf695 100644 --- a/appengine/ndb/modeling/structured_property_models_test.py +++ b/appengine/ndb/modeling/structured_property_models_test.py @@ -15,51 +15,44 @@ """Test classes for code snippet for modeling article.""" import structured_property_models as models -from testing import AppEngineTest -class ContactTestCase(AppEngineTest): - """A test case for the Contact model with StructuredProperty.""" - def setUp(self): - """Creates one Contact entity with 2 phone numbers.""" - super(ContactTestCase, self).setUp() - scott = models.Contact(name='scott') - scott.phone_numbers.append( - models.PhoneNumber(phone_type='home', - number='(650) 555 - 2200')) - scott.phone_numbers.append( - models.PhoneNumber(phone_type='mobile', - number='(650) 555 - 2201')) - scott.put() - self.scott_key = scott.key - - def test_phone_numbers(self): - """A test for 'phone_numbers' property.""" - scott = self.scott_key.get() - # make sure there are 2 numbers, you can expect the order is preserved. - self.assertEqual(len(scott.phone_numbers), 2) - self.assertEqual(scott.phone_numbers[0].phone_type, 'home') - self.assertEqual(scott.phone_numbers[0].number, '(650) 555 - 2200') - self.assertEqual(scott.phone_numbers[1].phone_type, 'mobile') - self.assertEqual(scott.phone_numbers[1].number, '(650) 555 - 2201') - - # filer scott's phone numbers by type - home_numbers = [phone_number for phone_number in scott.phone_numbers - if phone_number.phone_type == 'home'] - self.assertEqual(len(home_numbers), 1) - self.assertEqual(home_numbers[0].number, '(650) 555 - 2200') - - # delete scott's mobile phone - mobile_numbers = [phone_number for phone_number in scott.phone_numbers - if phone_number.phone_type == 'mobile'] - self.assertEqual(len(mobile_numbers), 1) - lost_phone = mobile_numbers[0] - scott.phone_numbers.remove(lost_phone) - # Updates the entity (resending all its properties over the wire). - scott.put() - - # make sure there's no mobile phone of scott - scott = self.scott_key.get() - self.assertEqual(len(scott.phone_numbers), 1) - self.assertEqual(scott.phone_numbers[0].phone_type, 'home') - self.assertEqual(scott.phone_numbers[0].number, '(650) 555 - 2200') +def test_phone_numbers(testbed): + # Create one Contact entity with 2 phone numbers. + scott = models.Contact(name='scott') + scott.phone_numbers.append( + models.PhoneNumber(phone_type='home', + number='(650) 555 - 2200')) + scott.phone_numbers.append( + models.PhoneNumber(phone_type='mobile', + number='(650) 555 - 2201')) + scott.put() + + # make sure there are 2 numbers, you can expect the order is preserved. + assert len(scott.phone_numbers) == 2 + assert scott.phone_numbers[0].phone_type == 'home' + assert scott.phone_numbers[0].number == '(650) 555 - 2200' + assert scott.phone_numbers[1].phone_type == 'mobile' + assert scott.phone_numbers[1].number == '(650) 555 - 2201' + + # filer scott's phone numbers by type + home_numbers = [phone_number for phone_number in scott.phone_numbers + if phone_number.phone_type == 'home'] + assert len(home_numbers) == 1 + assert home_numbers[0].number == '(650) 555 - 2200' + + # delete scott's mobile phone + mobile_numbers = [phone_number for phone_number in scott.phone_numbers + if phone_number.phone_type == 'mobile'] + assert len(mobile_numbers) == 1 + lost_phone = mobile_numbers[0] + scott.phone_numbers.remove(lost_phone) + + # Updates the entity (resending all its properties over the wire). + scott.put() + + # make sure there's no mobile phone of scott + scott = scott.key.get() + assert len(scott.phone_numbers) == 1 + assert scott.phone_numbers[0].phone_type == 'home' + assert scott.phone_numbers[0].number == '(650) 555 - 2200' diff --git a/appengine/ndb/overview/main_test.py b/appengine/ndb/overview/main_test.py index 8fbc5f9de5f..6abe11e8d42 100644 --- a/appengine/ndb/overview/main_test.py +++ b/appengine/ndb/overview/main_test.py @@ -13,14 +13,10 @@ # limitations under the License. import main -from testing import AppEngineTest import webtest -class TestHandlers(AppEngineTest): - def test_hello(self): - app = webtest.TestApp(main.app) - response = app.get('/') - - # Let's check if the response is correct. - self.assertEqual(response.status_int, 200) +def test_app(testbed): + app = webtest.TestApp(main.app) + response = app.get('/') + assert response.status_int == 200 diff --git a/appengine/ndb/transactions/main_test.py b/appengine/ndb/transactions/main_test.py index b7aa42e8e9e..43c6349bbbe 100644 --- a/appengine/ndb/transactions/main_test.py +++ b/appengine/ndb/transactions/main_test.py @@ -13,49 +13,37 @@ # limitations under the License. import main -from testing import AppEngineTest - - -class TestHandlers(AppEngineTest): - def setUp(self): - super(TestHandlers, self).setUp() - main.app.config['TESTING'] = True - self.app = main.app.test_client() - - def test_hello(self): - rv = self.app.get('/') - self.assertIn('Permenant note page', rv.data) - self.assertEqual(rv.status, '200 OK') - - def test_post(self): - rv = self.app.post('/add', data=dict( - note_title='Title', - note_text='Text' - ), follow_redirects=True) - self.assertEqual(rv.status, '200 OK') - - def test_post2(self): - rv = self.app.post('/add', data=dict( - note_title='Title2', - note_text='Text' - ), follow_redirects=True) - self.assertEqual(rv.status, '200 OK') - - def test_post3(self): - rv = self.app.post('/add', data=dict( - note_title='Title3', - note_text='Text' - ), follow_redirects=True) - self.assertEqual(rv.status, '200 OK') - - def test_there(self): - rv = self.app.post('/add', data=dict( - note_title='Title', - note_text='New' - ), follow_redirects=True) - rv = self.app.post('/add', data=dict( - note_title='Title', - note_text='There' - ), follow_redirects=True) - self.assertIn('Already there', rv.data) - self.assertEqual(rv.status, '200 OK') +import pytest + + +@pytest.fixture +def app(testbed): + main.app.config['TESTING'] = True + return main.app.test_client() + + +def test_index(app): + rv = app.get('/') + assert 'Permanent note page' in rv.data + assert rv.status == '200 OK' + + +def test_post(app): + rv = app.post('/add', data=dict( + note_title='Title', + note_text='Text' + ), follow_redirects=True) + assert rv.status == '200 OK' + + +def test_there(app): + rv = app.post('/add', data=dict( + note_title='Title', + note_text='New' + ), follow_redirects=True) + rv = app.post('/add', data=dict( + note_title='Title', + note_text='There' + ), follow_redirects=True) + assert 'Already there' in rv.data + assert rv.status == '200 OK' diff --git a/appengine/storage/main_test.py b/appengine/storage/main_test.py index 96787217fbf..fd9b9fd32b1 100644 --- a/appengine/storage/main_test.py +++ b/appengine/storage/main_test.py @@ -14,21 +14,16 @@ import re import main -import testing import webtest -class TestStorageSample(testing.AppEngineTest): +def test_get(cloud_config): + main.BUCKET_NAME = cloud_config.GCLOUD_PROJECT + app = webtest.TestApp(main.app) - def setUp(self): - super(TestStorageSample, self).setUp() - self.app = webtest.TestApp(main.app) - main.BUCKET_NAME = self.config.GCLOUD_PROJECT + response = app.get('/') - def test_get(self): - response = self.app.get('/') - - self.assertEqual(response.status_int, 200) - self.assertRegexpMatches( - response.body, - re.compile(r'.*.*items.*etag.*', re.DOTALL)) + assert response.status_int == 200 + assert re.search( + re.compile(r'.*.*items.*etag.*', re.DOTALL), + response.body) diff --git a/testing/__init__.py b/testing/__init__.py index b3373d37cd1..f5c1f76ce62 100644 --- a/testing/__init__.py +++ b/testing/__init__.py @@ -11,14 +11,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .appengine import AppEngineTest from .cloud import CloudTest from .flaky import flaky_filter, mark_flaky from .utils import capture_stdout, Http2Mock __all__ = [ - 'AppEngineTest', 'capture_stdout', 'CloudTest', 'flaky_filter', diff --git a/testing/appengine.py b/testing/appengine.py index 565ba8e0eb7..92b721afd2b 100644 --- a/testing/appengine.py +++ b/testing/appengine.py @@ -15,12 +15,9 @@ Common testing tools for Google App Engine tests. """ -import os import sys import tempfile -from nose.plugins.skip import SkipTest - try: APPENGINE_AVAILABLE = True from google.appengine.datastore import datastore_stub_util @@ -30,9 +27,6 @@ APPENGINE_AVAILABLE = False -from .cloud import CloudTest - - def setup_sdk_imports(): """Sets up appengine SDK third-party imports.""" if 'google' in sys.modules: @@ -59,70 +53,47 @@ def import_appengine_config(): pass -class AppEngineTest(CloudTest): - """A base test case for common setup/teardown tasks for test.""" - def setUp(self): - super(AppEngineTest, self).setUp() - - if not APPENGINE_AVAILABLE: - raise SkipTest() - - # A hack to prevent get_application_default from going GAE route. - self._server_software_org = os.environ.get('SERVER_SOFTWARE') - os.environ['SERVER_SOFTWARE'] = '' - - # Setup the datastore and memcache stub. - # First, create an instance of the Testbed class. - self.testbed = testbed.Testbed() - # Then activate the testbed, which prepares the service stubs for - # use. - self.testbed.activate() - # Create a consistency policy that will simulate the High - # Replication consistency model. - self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( - probability=0) - # Initialize the datastore stub with this policy. - self.testbed.init_datastore_v3_stub( - datastore_file=tempfile.mkstemp()[1], - consistency_policy=self.policy) - self.testbed.init_memcache_stub() - - # Setup remaining stubs. - self.testbed.init_app_identity_stub() - self.testbed.init_blobstore_stub() - self.testbed.init_user_stub() - self.testbed.init_taskqueue_stub(root_path='tests/resources') - self.taskqueue_stub = self.testbed.get_stub( - testbed.TASKQUEUE_SERVICE_NAME) - self.testbed.init_logservice_stub() - - def tearDown(self): - super(AppEngineTest, self).tearDown() - - if self._server_software_org: - os.environ['SERVER_SOFTWARE'] = self._server_software_org - - self.testbed.deactivate() - - def login_user(self, email='user@example.com', id='123', is_admin=False): - self.testbed.setup_env( - user_email=email, - user_id=id, - user_is_admin='1' if is_admin else '0', - overwrite=True) - - def run_tasks(self): - tasks = self.taskqueue_stub.get_filtered_tasks() - for task in tasks: - namespace = task.headers.get('X-AppEngine-Current-Namespace', '') - previous_namespace = namespace_manager.get_namespace() - try: - namespace_manager.set_namespace(namespace) - self.app.post( - task.url, - task.extract_params(), - headers={ - k: v for k, v in task.headers.iteritems() - if k.startswith('X-AppEngine')}) - finally: - namespace_manager.set_namespace(previous_namespace) +def setup_testbed(): + # Setup the datastore and memcache stub. + # First, create an instance of the Testbed class. + tb = testbed.Testbed() + # Then activate the testbed, which prepares the service stubs for + # use. + tb.activate() + # Create a consistency policy that will simulate the High + # Replication consistency model. + policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( + probability=0) + # Initialize the datastore stub with this policy. + tb.init_datastore_v3_stub( + datastore_file=tempfile.mkstemp()[1], + consistency_policy=policy) + tb.init_memcache_stub() + + # Setup remaining stubs. + tb.init_app_identity_stub() + tb.init_blobstore_stub() + tb.init_user_stub() + tb.init_logservice_stub() + # tb.init_taskqueue_stub(root_path='tests/resources') + tb.init_taskqueue_stub() + tb.taskqueue_stub = tb.get_stub(testbed.TASKQUEUE_SERVICE_NAME) + + return tb + + +def run_tasks(testbed, app): + tasks = testbed.taskqueue_stub.get_filtered_tasks() + for task in tasks: + namespace = task.headers.get('X-AppEngine-Current-Namespace', '') + previous_namespace = namespace_manager.get_namespace() + try: + namespace_manager.set_namespace(namespace) + app.post( + task.url, + task.extract_params(), + headers={ + k: v for k, v in task.headers.iteritems() + if k.startswith('X-AppEngine')}) + finally: + namespace_manager.set_namespace(previous_namespace) diff --git a/tox.ini b/tox.ini index 4946f9cd4cb..1a7c5b14f46 100644 --- a/tox.ini +++ b/tox.ini @@ -84,6 +84,7 @@ examples = appengine/logging/reading_logs appengine/logging/writing_logs appengine/mailgun + appengine/memcache/guestbook appengine/multitenancy appengine/ndb/modeling appengine/ndb/overview