{"id":10489,"date":"2016-08-18T15:48:27","date_gmt":"2016-08-18T13:48:27","guid":{"rendered":"https:\/\/blog.zhaw.ch\/icclab\/?p=10489"},"modified":"2016-08-18T15:50:50","modified_gmt":"2016-08-18T13:50:50","slug":"testing-pymongo-applications-with-mockupdb","status":"publish","type":"post","link":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/","title":{"rendered":"Testing PyMongo applications with MockupDB"},"content":{"rendered":"<p>In one of our projects, we needed to test some mongo based backend functionality: we wrote a small application which comprised of a mongo backend and a python app which communicated with the backend via pymongo. We like the flexibility of mongo in a rapid prototyping context and did not want to go with a full fledged ORM model for this app. Here we describe how we used MockupDB to perform some unit testing on this app.<!--more--><\/p>\n<p>PyMongo is the <a href=\"https:\/\/docs.mongodb.com\/ecosystem\/drivers\/python\/#python-driver\">official<\/a> Python driver for connecting Mongo databases: it has a full set of features for managing documents and also a large set of <a href=\"http:\/\/api.mongodb.com\/python\/current\/tools.html\">tools and frameworks<\/a> that can be used in conjunction with PyMongo. Despite this rich ecosystem, there is little documentation on best practices for testing PyMongo applications &#8211; <a href=\"https:\/\/github.com\/theorm\/mongobox\">mongobox<\/a> is provided \u00a0as a framework tool for testing; its model is one in which a MongoDB instance is created with a temporary directory to store database files for testing &#8211; this solution can be heavy for some types of testing, unit testing in particular.<\/p>\n<p>Just recently when looking for approaches to testing our web-based application we found <a href=\"https:\/\/emptysqua.re\/blog\/black-pipe-testing-series\/\">MockupDB<\/a>, a <a href=\"http:\/\/docs.mongodb.org\/meta-driver\/latest\/legacy\/mongodb-wire-protocol\/\">wire protocol<\/a> server for MongoDB. MockupDB fits pretty much our testing requirements &#8211; we needed to test mostly CRUD operations in the REST API interface of our application, which connects to a mongo database and reads or modifies the content of documents before serving them. But MockupDB goes beyond that, allowing testing pattern-matching, cursor failure, request failure and <a href=\"http:\/\/mockupdb.readthedocs.io\/tutorial.html\">much more<\/a>.<\/p>\n<p>Here is an example of a test used as starting point for our application (it uses the standard python testing conventions).<\/p>\n<pre><code>\r\n# test_database.py\r\n\r\nfrom mockupdb import go, MockupDB\r\nimport unittest\r\nImport datetime\r\n\r\n# Our own database class using PyMongo\r\nfrom database import MongoDatabase\r\n\r\nDOCUMENT = {\"_id\": \"123ab-456cd-789ef\", 'name': \"abc123\",\r\n\r\n\"flavor_id\": 1, \"image_id\": 2, \"job_duration\": 120}\r\n\r\nclass MockupDBDatabaseTest(unittest.TestCase):\r\n\r\n    def setUp(self):\r\n        self.server = MockupDB(auto_ismaster={\"maxWireVersion\": 3})\r\n        self.server.run()\r\n\r\n        # Replace pymongo connection url to use MockupDB\r\n        self.database = MongoDatabase(self.server.uri)\r\n\r\n    def tearDown(self):\r\n        self.server.stop()\r\n\r\n    def test_list_documents(self):\r\n        document = DOCUMENT\r\n\r\n        # adding datetime object to document\r\n        document['request_time'] = datetime.datetime.now()\r\n\r\n        # The database list method converts any datetime object returned\r\n        # from the database to string. See below.\r\n        document_query = go(self.database.list, {})\r\n\r\n        request = self.server.receives()\r\n\r\n        # returns to pymongo a list containing only 1 the document\r\n        request.reply([DOCUMENT])\r\n\r\n        self.assertIsInstance(document_query()[0]['request_time'], str)\r\n        self.assertEqual(\r\n            document['request_time'].strftime(\"%Y-%m-%dT%H:%M:%S\"),\r\n            document_query()[0]['request_time']\r\n        )\r\n\r\n# database.py\r\n\r\nclass MongoDatabase(object):\r\n    def __init__(self, uri):\r\n        self.client = MongoClient(uri)\r\n        self.db = self.client.db\r\n        self.collection = self.db.collection\r\n\r\n    def list(self, query):\r\n        data_list = list()\r\n        for data in self.collection.find(query):\r\n            data['id'] = str(data.pop('_id'))\r\n            data = self._convert_datetime_to_str(data)\r\n            data_list.append(data)\r\n        return data_list\r\n\r\n    def _convert_datetime_to_str(self, data):\r\n        for key in data.keys():\r\n            if isinstance(data[key], datetime.datetime):\r\n                data[key] = data[key].strftime('%Y-%m-%dT%H:%M:%S')\r\n        return data\r\n<\/code><\/pre>\n<p>MockupDB was the first solution we came across when looking for alternatives to unit testing pymongo methods, subsequently we also found a few other packages mocking MongoDB &#8211; <a href=\"https:\/\/github.com\/mongomock\/mongomock\">Mongomock<\/a> and <a href=\"http:\/\/ming.readthedocs.io\/en\/latest\/\">Ming<\/a> (with its mongo in memory module), although we have not had a chance to look into these as yet.<\/p>\n<p>Generally, MockupDB is a powerful yet flexible package which can be used for both simple and more complex testing cases providing simple functions with a very small learning curve. So far we have only used it for simple unit tests but we are also keen to try out more complex scenarios with e.g. multiple MongoDB configurations where there are network failures.<\/p>\n<p>If you are interested in more information about MockupDB and testing examples you can check these links:<\/p>\n<ul>\n<li><a href=\"https:\/\/emptysqua.re\/blog\/black-pipe-testing-series\/\">Black Pipe Testing series<\/a> &#8211; an interesting testing concept evolved from classical black box testing with single input and output to entities which have multiple inputs and outputs (eg northbound and southbound interfaces)<\/li>\n<li><a href=\"https:\/\/github.com\/ajdavis\/pymongo-mockup-tests\/tree\/master\/tests\">Example of MockupDB tests<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><i>Hat tip to <\/i><a href=\"https:\/\/twitter.com\/jdrumgoole\"><i>Joe Drumgoole<\/i><\/a><i> for pointing us in the right direction and to <\/i><a href=\"https:\/\/twitter.com\/jessejiryudavis\"><i>Jesse Jiryu Davis<\/i><\/a><i> who did the hard work of writing MockupDB<\/i>!<\/p>\n<div class=\"pt-sm\">Schlagw\u00f6rter: <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/black-pipe-testing\/\">black pipe testing<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/mockupdb\/\">mockupdb<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/mongodb\/\">mongodb<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/pymongo\/\">pymongo<\/a>, <a href=\"https:\/\/blog.zhaw.ch\/icclab\/tag\/testing\/\">testing<\/a><br><\/div>","protected":false},"excerpt":{"rendered":"<p>In one of our projects, we needed to test some mongo based backend functionality: we wrote a small application which comprised of a mongo backend and a python app which communicated with the backend via pymongo. We like the flexibility of mongo in a rapid prototyping context and did not want to go with a [&hellip;]<\/p>\n","protected":false},"author":101,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1,15],"tags":[801,800,433,799,330],"features":[],"class_list":["post-10489","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-howtos","tag-black-pipe-testing","tag-mockupdb","tag-mongodb","tag-pymongo","tag-testing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Testing PyMongo applications with MockupDB - Service Engineering (ICCLab &amp; SPLab)<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Testing PyMongo applications with MockupDB\" \/>\n<meta property=\"og:description\" content=\"In one of our projects, we needed to test some mongo based backend functionality: we wrote a small application which comprised of a mongo backend and a python app which communicated with the backend via pymongo. We like the flexibility of mongo in a rapid prototyping context and did not want to go with a [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\" \/>\n<meta property=\"og:site_name\" content=\"Service Engineering (ICCLab &amp; SPLab)\" \/>\n<meta property=\"article:published_time\" content=\"2016-08-18T13:48:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-08-18T13:50:50+00:00\" \/>\n<meta name=\"author\" content=\"Bruno Grazioli\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bruno Grazioli\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\"},\"author\":{\"name\":\"Bruno Grazioli\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\"},\"headline\":\"Testing PyMongo applications with MockupDB\",\"datePublished\":\"2016-08-18T13:48:27+00:00\",\"dateModified\":\"2016-08-18T13:50:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\"},\"wordCount\":468,\"commentCount\":0,\"keywords\":[\"black pipe testing\",\"mockupdb\",\"mongodb\",\"pymongo\",\"testing\"],\"articleSection\":[\"*.*\",\"HowTos\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\",\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\",\"name\":\"Testing PyMongo applications with MockupDB - Service Engineering (ICCLab &amp; SPLab)\",\"isPartOf\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#website\"},\"datePublished\":\"2016-08-18T13:48:27+00:00\",\"dateModified\":\"2016-08-18T13:50:50+00:00\",\"author\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\/\/blog.zhaw.ch\/icclab\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Testing PyMongo applications with MockupDB\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#website\",\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/\",\"name\":\"Service Engineering (ICCLab &amp; SPLab)\",\"description\":\"A Blog of the ZHAW Zurich University of Applied Sciences\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.zhaw.ch\/icclab\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba\",\"name\":\"Bruno Grazioli\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g\",\"caption\":\"Bruno Grazioli\"},\"url\":\"https:\/\/blog.zhaw.ch\/icclab\/author\/gaea\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Testing PyMongo applications with MockupDB - Service Engineering (ICCLab &amp; SPLab)","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/","og_locale":"en_US","og_type":"article","og_title":"Testing PyMongo applications with MockupDB","og_description":"In one of our projects, we needed to test some mongo based backend functionality: we wrote a small application which comprised of a mongo backend and a python app which communicated with the backend via pymongo. We like the flexibility of mongo in a rapid prototyping context and did not want to go with a [&hellip;]","og_url":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/","og_site_name":"Service Engineering (ICCLab &amp; SPLab)","article_published_time":"2016-08-18T13:48:27+00:00","article_modified_time":"2016-08-18T13:50:50+00:00","author":"Bruno Grazioli","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Bruno Grazioli","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#article","isPartOf":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/"},"author":{"name":"Bruno Grazioli","@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba"},"headline":"Testing PyMongo applications with MockupDB","datePublished":"2016-08-18T13:48:27+00:00","dateModified":"2016-08-18T13:50:50+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/"},"wordCount":468,"commentCount":0,"keywords":["black pipe testing","mockupdb","mongodb","pymongo","testing"],"articleSection":["*.*","HowTos"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/","url":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/","name":"Testing PyMongo applications with MockupDB - Service Engineering (ICCLab &amp; SPLab)","isPartOf":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/#website"},"datePublished":"2016-08-18T13:48:27+00:00","dateModified":"2016-08-18T13:50:50+00:00","author":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba"},"breadcrumb":{"@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.zhaw.ch\/icclab\/testing-pymongo-applications-with-mockupdb\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/blog.zhaw.ch\/icclab\/"},{"@type":"ListItem","position":2,"name":"Testing PyMongo applications with MockupDB"}]},{"@type":"WebSite","@id":"https:\/\/blog.zhaw.ch\/icclab\/#website","url":"https:\/\/blog.zhaw.ch\/icclab\/","name":"Service Engineering (ICCLab &amp; SPLab)","description":"A Blog of the ZHAW Zurich University of Applied Sciences","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.zhaw.ch\/icclab\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.zhaw.ch\/icclab\/#\/schema\/person\/769a2455bfa3cbcc87857218f19abeba","name":"Bruno Grazioli","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/07d475be0415d5914aa49599b3295e4d972f971e46f5d7ab89d474327ab7b5f0?s=96&d=mm&r=g","caption":"Bruno Grazioli"},"url":"https:\/\/blog.zhaw.ch\/icclab\/author\/gaea\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10489","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/users\/101"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/comments?post=10489"}],"version-history":[{"count":4,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10489\/revisions"}],"predecessor-version":[{"id":10493,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/posts\/10489\/revisions\/10493"}],"wp:attachment":[{"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/media?parent=10489"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/categories?post=10489"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/tags?post=10489"},{"taxonomy":"features","embeddable":true,"href":"https:\/\/blog.zhaw.ch\/icclab\/wp-json\/wp\/v2\/features?post=10489"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}