20

My application depends on request.remote_addr which is None when i run tests through nosetests which uses app.test_client().post('/users/login', ....).

How can I emulate an IP (127.0.0.1 works fine) when I run tests? I've tried setting environment variables, sent in headers with the post() method and I've digged through nosetests, werkzeugs and flasks documentation but nothing I've tried has worked.

Paco
  • 4,520
  • 3
  • 29
  • 53
moodh
  • 2,661
  • 28
  • 42
  • Possible duplicate of [Setting (mocking) request headers for Flask app unit test](http://stackoverflow.com/questions/15278285/setting-mocking-request-headers-for-flask-app-unit-test) – styvane Dec 08 '16 at 13:35
  • @Styvane: Uhm, this question is a month older, how is it a duplicate? – moodh Dec 08 '16 at 15:24
  • Perhaps I didn't choose the right question but [yes it is possible](http://meta.stackexchange.com/questions/147643/should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer-and-ha/147651#147651) – styvane Dec 08 '16 at 15:37

3 Answers3

27

You can set options for the underlying Werkzeug environment using environ_base:

from flask import Flask, request
import unittest

app = Flask(__name__)
app.debug = True
app.testing = True

@app.route('/')
def index():
    return str(request.remote_addr)

class TestApp(unittest.TestCase):

    def test_remote_addr(self):
        c = app.test_client()
        resp = c.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
        self.assertEqual('127.0.0.1', resp.data)


if __name__ == '__main__':
    unittest.main()
DazWorrall
  • 13,682
  • 5
  • 43
  • 37
  • Thanks, it works perfectly but having to append that on every single call would get tedious. A friend gave me a solution for fix that changes every call. Posting it as an answer as well. – moodh Feb 14 '13 at 10:52
  • +1 This appears to be the way werkzeug intended you to do this and was exactly what I was looking for – anthony sottile Sep 23 '13 at 00:37
  • Now my tests are passing in instances that needs to have a valid IP. Thanks. – iChux Aug 04 '16 at 09:47
8

A friend gave me this solution, which works across all requests:

class myProxyHack(object):

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        environ['REMOTE_ADDR'] = environ.get('REMOTE_ADDR', '127.0.0.1')
        return self.app(environ, start_response)

app.wsgi_app = myProxyHack(app.wsgi_app)

app.test_client().post(...)
moodh
  • 2,661
  • 28
  • 42
0

You can also pass a header param to the test_request_context if you prefer.

Example:

from flask import Flask, request
import unittest

app = Flask(__name__)
app.debug = True
app.testing = True

@app.route('/')
def index():
    return str(request.remote_addr)

class TestApp(unittest.TestCase):

    def test_headers(self):
        user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0"
        ip_address = 127.0.0.1
        headers = {
            'Remote_Addr': ip_address,
            'User_Agent': user_agent
        }

        with self.test_request_context(headers=headers):
            # Do something
            pass

This is useful when you need to perform several unit tests using the request object in other modules.

See the test_request_context documentation.