Concepts, use and testing Cloud Datastore in local.

585 views
Skip to first unread message

Juan Antonio Fernández Sánchez

unread,
Jun 10, 2016, 7:55:30 AM6/10/16
to Google App Engine

I'm really confused with the way to try Datastore in local. Please, give me a minute to explain.

I'm developing a app composed to few microservices like a only gae app. In a  parte of the app, I use the datastore. So when I run my app, I use the development server and when I save something in the datastore calling some method I can see perfectly the entity in the gae's admin web portal.

Well, now, instead of calling directly to ndb library and his methods I've built a  small library over ndb to abstract his functionallity, then I can call insertUser() instead of work directly with ndb. So, the problems appear when I try test this small library that I built (I've written a test.py file to do this).
At first, I thought  that this does not  can work because this test was executing without the deveserver running. After I searched info about how simulated the datastore in the local and I found this, but after I found too the unittest in local with the stubs, and now I don't understand nothing.

I've tried both (gcloud datastore emulator and stub with unittest)  and I don't get  do simple example:
I want test that a entity is saved in Datastore and after I want test that I can read this entity

I suppose that dev_server (in SDK) emulate the datastore (because I can see the list of my entities there), but then, why use the datastore emulator in local dev?, and then, why is necesary uses the stub to datastore if we have a datastore emulator to do all test that I want? I don't understand.

I understand that maybe my question is more of concepts than code but I need understand really right how is the best way to work with this.

LocalDev Server --> https://cloud.google.com/appengine/docs/python/tools/using-local-server
UnitTest with Stub --> https://cloud.google.com/appengine/docs/python/tools/localunittesting
DataStore Emulator --> https://cloud.google.com/datastore/docs/tools/datastore-emulator

Thanks you so much, any help will be welcome :)

Anastasios Hatzis

unread,
Jun 10, 2016, 10:14:22 AM6/10/16
to google-a...@googlegroups.com
Juan,

I do local testing with the GAE development server, Python unittest and Pylon's test framework WebTest. I use the datastore stub, too, and some other stubs.

My app is based on my own framework with plenty of specific stuff, but I haven't wrapped the NDB library. However, you probably don't need to care about your NDB wrapper, since you can just test your handlers like any other client (and with plain NDB calls, e.g. ndb.Query(), or key.get() to validate what actually is in the datastore while running a test.

Maybe this is all you will need: write some test-only handlers that demonstrate features of your NDB wrapper or framework. Then write some tests that just use HTTP request/response and maybe simple NDB calls to verify your NDB wrapper is intact.

This is an example how I test handlers:
import unittest

class MyTestCase(unittest.TestCase):
def setup()
import webtest # app from your webapp2.WSGIApplication() for example
self.testapp = webtest.TestApp(app)
self.testbed = testbed.Testbed()
self.testbed.activate()
# Create a consistency policy that will simulate the # High Replication consistency model.
# See https://cloud.google.com/appengine/docs/python/tools/localunittesting#Python_Writing_High_Replication_Datastore_tests
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1)
# Initialize the datastore stub with this policy.
self.testbed.init_datastore_v3_stub(consistency_policy=self.policy)
# you eventually want to add more stubs
# ...
# Clear ndb's in-context cache between tests.
# This prevents data from leaking between tests.
# Alternatively, you could disable caching by
# using ndb.get_context().set_cache_policy(False)
# ndb.get_context().clear_cache()
ndb.get_context().set_cache_policy(False)

# If you need initial data in datastore for test, # add them here (probably better to use the original NDB lib)

def tearDown(self):
self.testbed.deactivate()

def testCreateRead(self):
"""Test the handler that create objects of entity kind 'Foo' and the handler that read Foo object with given ID.
POST request will return a JSON object which contains the created foo objects in the `results` array
GET request will return a JSON object which represents the retrieved foo object

"""
# POST request to produce 2 foo objects, each with title
payload = [
{'title': 'hello'},
{'title': 'world'}
]
response = self.testapp.post_json('/api/v1/foos/create', payload, headers={'Accept': 'application/json'}, status='*')
# assertions as in https://docs.python.org/2/library/unittest.html#test-cases
self.assertEqual(response.status_int, 201)
self.assertTrue('results' in response.json, 'response to create foos has no results array')
self.assertDictEqual(response.json, {'results': [{'id': 1, 'title': 'hello'}, {'id': 2, 'title': 'world'}]}, 'result in create foo response is wrong')
# you can also use NDB in tests
self.assertEqual(ndb.Query(kind='Foo').count(), 2, 'expected 2 foo created')

# GET request with JSON response
response = self.testapp.get('/api/v1/foo/1', headers={'Accept': 'application/json'}, status='*', xhr=True)
self.assertEqual(response.status_int, 200)
self.assertDictEqual(response.json, {'id': 1, 'title': 'hello'}, 'response to getting foo #1 is wrong')

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

I haven't run this particular code sample though ;-)

Good luck,
Ani


--
You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-appengi...@googlegroups.com.
To post to this group, send email to google-a...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-appengine.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-appengine/cd123e20-c5fc-4faa-8717-49ddd012bd22%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Mit freundlichen Grüßen / Kind regards

i. A.
Anastasios Hatzis

Fon: +49 8374 930813
Fax: +49 8374 930810
Mobil: +49 1520 8592878

HATZIS Edelstahlbearbeitung GmbH
Hojen 2
87490 Haldenwang (Allgäu)
Germany

Handelsregister Kempten (Allgäu): HRB 4204
Geschäftsführer: Paulos Hatzis, Charalampos Hatzis
Umsatzsteuer-Identifikationsnummer: DE 128791802
GLN: 42 504331 0000 6

http://www.hatzis.de/

Alex Martelli

unread,
Jun 10, 2016, 10:15:53 AM6/10/16
to google-a...@googlegroups.com
The testbed provides stubs for App Engine services (in the original sense of the word, not, as used today, as a renaming of what used to be called App Engine modules) which let you control precisely the entire setup in which you unit-test your Python code meant to run in App Engine. It deals with App Engine only, and is optimal for small setups entirely under your control.

The datastore API (still in beta) is not specific to App Engine -- see https://cloud.google.com/datastore/docs/concepts/overview for a general overview of the product, and https://cloud.google.com/datastore/docs/client-libraries for more about it.

The emulator tool complements the API by letting you test systems using the API (whether they're meant to run in App Engine, elsewhere, or a mix) typically in situations where persistence helps (you don't setup the datastore state anew for every test, so it can, if needed, be a pretty substantial state) -- essentially, integration tests, for the most part (though nothing stops you from using the emulator for unit tests, the testbed is usually handier for the latter if your code is meant to run in App Engine).

Unit and integration tests are not mutually exclusive: to make your code highly reliable, you should cover it well with both kinds of tests. The testbed and the emulator give you the underlying tools to do exactly that.


Alex

--

Vitaly Bogomolov

unread,
Jun 10, 2016, 3:34:52 PM6/10/16
to Google App Engine
Hi.
 
I'm really confused with the way to try Datastore in local. Please, give me a minute to explain.

read this:

into test.py, that runs test suite (for example):

import sys, os
import unittest
 
app_engine = r"C:\Program Files (x86)\Google\google_appengine"
sys.path.insert(1, app_engine)
sys.path.insert(1, os.path.join(app_engine, 'lib', 'yaml', 'lib'))
 
import dev_appserver
 
dev_appserver.fix_sys_path()
suite = unittest.TestLoader().discover('.')
unittest.TextTestRunner().run(suite)

base class for GAE-specific unit tests:

import os
import unittest
from google.appengine.ext import testbed

 
class GaeTestCase(unittest.TestCase):
    def setUp(self):
        # 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()
        # Next, declare which service stubs you want to use.
        self.testbed.init_datastore_v3_stub()  # it's need for datastore tests
        self.testbed.init_memcache_stub()
        self.testbed.init_app_identity_stub()
        self.testbed.init_blobstore_stub()
        self.testbed.init_files_stub()
        self.testbed.init_taskqueue_stub(root_path="path_to_your_project")
        self.taskqueue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME)
        self.testbed.init_urlfetch_stub()
        self.testbed.init_user_stub()
    def tearDown(self):
        self.testbed.deactivate()

WBR, Vitaly

Juan Antonio Fernández Sánchez

unread,
Jun 11, 2016, 3:08:13 PM6/11/16
to Google App Engine
First for all,
Thanks thanks thanks you so much for all the help guys!

I think that I'm starting to understand. When I use the dev server he start much of services. But when I execute the test with testbed and datastore_v3_stub this stub emulated only the datastore. And if I was using other tools that i would connect to Cloud Datastore maybe I will need use the datastore emulator.

But in this case, why don't use the own development server which I use to run my app to test my lib (ndb wrapper) or anything ?

Anyway, I'm using testbed and it works fine, but I' ve found a problem, when I execute a test over the method that insert a student in the datastore all work fine, I check that the user is inserted. But after when I check other method that read specific user I see that I dont have entities that read. I don't understand why if both methods are in the same Test  class and one is after other.
Any idea?

Vitaly Bogomolov

unread,
Jun 11, 2016, 3:44:38 PM6/11/16
to Google App Engine
Anyway, I'm using testbed and it works fine, but I' ve found a problem, when I execute a test over the method that insert a student in the datastore all work fine, I check that the user is inserted. But after when I check other method that read specific user I see that I dont have entities that read. I don't understand why if both methods are in the same Test  class and one is after other.
Any idea?

Alex Martelli

unread,
Jun 11, 2016, 9:25:23 PM6/11/16
to google-a...@googlegroups.com
On Sat, Jun 11, 2016 at 12:08 PM, Juan Antonio Fernández Sánchez <juan.antonio.fer...@gmail.com> wrote:
First for all,
Thanks thanks thanks you so much for all the help guys!

I think that I'm starting to understand. When I use the dev server he start much of services. But when I execute the test with testbed and datastore_v3_stub this stub emulated only the datastore. And if I was using other tools that i would connect to Cloud Datastore maybe I will need use the datastore emulator.

But in this case, why don't use the own development server which I use to run my app to test my lib (ndb wrapper) or anything ?

I find "in this case" ambiguous since you've just mentioned TWO different cases. The closest one, to which "this" would refer in English (and "questo" in Italian; does "esto" work differently in Spanish?), obviously you don't use the development server, because it runs an emulation of App Engine datastore, not the Cloud Datastore as the emulator does.

If you meant the other case, where you just want to test the app engine datastore usage by your app engine code, you've just explained why not use the dev server: it starts many services, so it's not ideal for a UNIT test, where you're testing just one "unit" (a single class or function in your application) -- the TESTBED is ideal for UNIT tests. Integration tests are a very different matter.

Similarly, the fact that with the testbed you easily "clean up" between tests ensures the order in which tests execute (which is kind of random) doesn't affect the result -- absolutely crucial in all kinds of tests. From the rest of your mail you seem to WANT for tests to affect each other, but that makes no sense to me (most especially since you don't control the order in which tests execute), so it's more likely that I'm 100% misunderstanding what you write.


Alex

 

Anyway, I'm using testbed and it works fine, but I' ve found a problem, when I execute a test over the method that insert a student in the datastore all work fine, I check that the user is inserted. But after when I check other method that read specific user I see that I dont have entities that read. I don't understand why if both methods are in the same Test  class and one is after other.
Any idea?

--
You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-appengi...@googlegroups.com.
To post to this group, send email to google-a...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-appengine.
Reply all
Reply to author
Forward
0 new messages