I am trying to mock test an endpoint that gets the time and date.
I have viewed several tutorials and python docs, but I am still getting stumped by the mock test.
Any help is appreciated greatly
from flask import Flask, redirect, url_for
import json
import urllib.request
import requests
app = Flask(__name__)
#app.route('/')
def welcome():
return "Hello"
#app.route('/<zone>')
def Endpoint(zone):
address = f"http://worldclockapi.com/api/json/{zone}/now"
response = urllib.request.urlopen(address)
result = json.loads(response.read())
time = result['currentDateTime']
return time
if __name__ == "__main__":
app.run(debug=True)
My attempt.
I think I am still calling the external element.
I want to use a fake JSON string and actually mock with that.
The first test passes when I run it. But I don't think it is a true mock.
#!/usr/bin/python
import unittest
from unittest import TestCase
from unittest.mock import patch, Mock
#name of endpoint program
import question
class TestingMock(TestCase):
#patch('question.Endpoint')
def test_call(self, MockTime):
current = MockTime()
current.posts.return_value = [
{"$id": "1", "currentDateTime": "2020-07-17T12:31-04:00", "utcOffset": "-04:00:00"}
]
response = current.posts()
self.assertIsNotNone(response)
self.assertIsInstance(response[0], dict)
#patch('question.Endpoint')
def test_response(mock_get):
mock_get.return_value.ok = True
respond = question.Endpoint()
assert_is_not_none(respond)
if __name__ == '__main__':
unittest.main()
You are conflicting with your root URL handler. Try changing #app.route('/<zone>') to #app.route('/time/<zone>'), then navigate to that url
Related
I am trying to get coverage up on my Python code and am testing my Flask app. Without being too specific, let's look at the sample code here:
# from /my_project/app_demo/app.py
from private_module import logs
from flask import Flask
import logging
logs.init_logging()
logger = logging.getLogger(__name__)
app = Flask(__name__)
#app.route("/greet/<name:name>", methods=["GET"])
def greet(name):
logger.info(f"{name} wants a greeting")
return f"Hello, {name}!"
if __name__ == "__main__":
app.run(debug=True)
If I am to write a unit test for the greet function, I want to mock the logger to assert it is called when it is created and when the info method is called. For this example, the sources root folder is app_demo and there is an init.py in that python folder.
# from /my_project/tests/test_app.py
import pytest
from unittest import mock
#pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_greet(client):
logs_mock = mock.patch("app_demo.app.logs.init_logging")
logger_mock = mock.patch("app_demo.app.logging.getLogger")
actual = client.get("George")
assert "Hello, George!" == actual
# these next assertions do not work
logs_mock.assert_called_once_with()
logging_mock.assert_called_once_with("app_demo.app") # not sure if this will be "__main__"
logging_mock.return_value.info.assert_called_once_with("George wants a greeting")
If I debug where the logger.info is called in the greet function, the object is a logger and not the mock object I want it to be.
I have tried making the mock in another fixture as well but that did not make it work either.
import flask
import sentimentanalyzer
app: object = flask
#app.route("/")
def default() :
return "Hello world>>!!"``
#app.route("/predictsentiment/<query>",method=['GET'])
def predict(query):
sentiment = sentimentanalyzer.returnSentiment(query)
return flask.jsonify(sentiment)
if __name__ == "__main__":
app.run()
You need to import Flask class from flask module.
from flask import Flask
import sentimentanalyzer
app = Flask(__name__)
#app.route("/")
def default() :
return "Hello world>>!!"
#app.route("/predictsentiment/<query>",methods=['GET'])
def predict(query):
sentiment = sentimentanalyzer.returnSentiment(query)
return flask.jsonify(sentiment)
if __name__ == '__main__':
app.run()
I see you have not found a solution yet.
from flask import Flask
import sentimentanalyzer
app = Flask(__name__)
#app.route("/")
def default() :
return "Hello world>>!!"
#app.route("/predictsentiment/<query>",methods=['GET'])
def predict(query):
sentiment = sentimentanalyzer.returnSentiment(query)
return flask.jsonify(sentiment)
if __name__ == '__main__':
app.run()
Though the above code is correct, your error may be the initialization or the structure of the app. Please post the structure.
init.py needs to be put in a directory and the directory is called.
Try renaming your init.py to app.py, should solve the error.
As a reference the Quickstart docs here: https://flask.palletsprojects.com/en/1.1.x/quickstart/
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
You need to create an object from the Flask class to get started.
And methods needs to be plural. (ref: https://flask.palletsprojects.com/en/1.1.x/quickstart/#http-methods)
Not relevant tot the question the default route has invalid syntax with the double backticks resulting in:
File "/home/tom/tmp/test.py", line 8
return "Hello world>>!!"``
^
SyntaxError: invalid syntax
Regards,
Tom
You need to import the flask class from the flask module. Check how to make minimal application here
import flask
import sentimentanalyzer
app: flask.Flask = flask.Flask(__name__)
#app.route("/")
def default() :
return "Hello world>>!!"
#app.route("/predictsentiment/<query>")
def predict(query):
sentiment = sentimentanalyzer.returnSentiment(query)
return flask.jsonify(sentiment)
if _name_== " main ":
app.run()
I would like to write unit test for web.py application by using pytest. How to invoke the web.py services in pytest.
Code:
import web
urls = (
'/', 'index'
)
app = web.application(urls, globals())
class index:
def GET(self):
return "Hello, world!"
if __name__ == "__main__":
app.run()
It can be done by using python requests module, when we run the web.py services, it will run http://localhost:8080/. Then import requests module and use get method and in response object, you can verify the result. That's fine.
By using Paste and nose also we can achieve this as per web.py official documentation. http://webpy.org/docs/0.3/tutorial.
Is there any solution in pytest like option in paste and nose.
Yes. Actually the code from the web.py recipe Testing with Paste and Nose could be used with py.test almost as is, just removing the nose.tools import and updating assertions appropriately.
But if you want to know how to write tests for web.py applications in the py.test style, they could look like this:
from paste.fixture import TestApp
# I assume the code from the question is saved in a file named app.py,
# in the same directory as the tests. From this file I'm importing the variable 'app'
from app import app
def test_index():
middleware = []
test_app = TestApp(app.wsgifunc(*middleware))
r = test_app.get('/')
assert r.status == 200
assert 'Hello, world!' in r
As you will add further tests, you will probably refactor creation of the test app out to a fixture:
from pytest import fixture # added
from paste.fixture import TestApp
from app import app
def test_index(test_app):
r = test_app.get('/')
assert r.status == 200
assert 'Hello, world!' in r
#fixture()
def test_app():
middleware = []
return TestApp(app.wsgifunc(*middleware))
I'm trying test my falcon routes, but tests always failed, and looks like I make all things right.
my app.py
import falcon
from resources.static import StaticResource
api = falcon.API()
api.add_route('/', StaticResource())
and my test directory tests/static.py
from falcon import testing
import pytest
from app import api
#pytest.fixture(scope='module')
def client():
# Assume the hypothetical `myapp` package has a
# function called `create()` to initialize and
# return a `falcon.API` instance.
return testing.TestClient(api.create())
def test_get_message(client):
result = client.simulate_get('/')
assert result.status_code == 200
Help please, why I got AttributeError: 'API' object has no attribute 'create'
error? Thanks.
You are missing the hypothetical create() function in your app.py.
Your app.py should look like the following:
import falcon
from resources.static import StaticResource
def create():
api = falcon.API()
api.add_route('/', StaticResource())
return api
api = create()
Then in your tests/static.py should look like:
from falcon import testing
import pytest
from app import create
#pytest.fixture(scope='module')
def client():
return testing.TestClient(create())
def test_get_message(client):
result = client.simulate_get('/')
assert result.status_code == 200
The tornado testing subject doc is so simple, I am not quite sure how to do a unit test on tornado. like that:
here is a api.py:
import tornado
import logging
from tornado.web import RequestHandler
import time
class AnalyticsBWSpecificHour(RequestHandler):
def get(self):
return self.write({'message':'no get method'})
class Application(tornado.web.Application):
def __init__(self,**kwargs):
api_handlers = [
(r"/", AnalyticsBWSpecificHour),
]
logging.debug(api_handlers)
super(Application, self).__init__(api_handlers, **kwargs)
and the test_tornado.py :
from api import Application
from tornado.testing import AsyncHTTPTestCase
import tornado
import logging
logging.basicConfig(level=logging.DEBUG)
import unittest
class ApiTestCase(AsyncHTTPTestCase):
def get_app(self):
self.app = Application(debug=True)
return self.app
def test_status(self):
print(self.get_url('/'))
response = self.fetch(self.get_url('/'),method='GET')
self.assertEqual(response.code,200)
if __name__ == '__main__':
unittest.main()
even this is quite simple example, I also get the 599 error. please help me.
response = self.fetch(self.get_url('/'),method='GET')
self.fetch() calls self.get_url for you. Either do self.fetch('/') or self.http_client.fetch(self.get_url('/')), but don't mix the two.
Also don't pass debug=True in tests; the autoreload will do the wrong thing in a unittest environment.