1
votes

i am trying to test flask application with flask client.

My app route handling is as follows

@app.route('/', methods=['post', 'get'])
@app.route('/index', methods=['post', 'get'])
def index():

   login_form = LoginForm(request.form)
   logout_form = LogoutForm(request.form)
   short_url_form = ShortURLForm(request.form)


   if request.method == 'POST' and short_url_form.validate():
       url = short_url_form.url.data
       url_shortener_handler = urlShortener()

       app.logger.debug('in post method to shorten Url(%s)', url)

       # TODO have a mechanism for handling duplicate key error
       short_url = url_shortener_handler.generateShortUrl()

       if url_shortener_handler.saveUrl(short_url, url):
           app.logger.debug('value of short url(%s) for url is (%s)', short_url, url)
           return render_template('index.html',
                               login_form=login_form,
                               logout_form=logout_form,
                               shorturl_form=short_url_form,
                               shortURL=SITE_URL + '/' + short_url)
       else:
          app.logger.critical('Error in saving short url(%s) for url is (%s)', short_url, url)
          flash('Internal error try again')

    return render_template('index.html',
                       login_form=login_form,
                       logout_form=logout_form,
                       shorturl_form=short_url_form,
                       shortURL=None)

And the short_url_form is defined as below

class ShortURLForm(Form):

    url = StringField('url', validators=[url(), data_required()])
    submit = SubmitField('Shorten')

    def __init__(self, *args, **kwargs):
       Form.__init__(self, *args, **kwargs)

    def validate(self):
       """  performs validation of input  """
       if not Form.validate(self):
          return False
       return True

And i am testing with the test case as follows

 class TestBasicUrlShortener(unittest.TestCase):
    def setUp(self):
       self.client = app.test_client()
       self.baseURL = 'http://localhost:5000'

    def create_app(self):
         """  this is one of the functions that must be implemented for flask testing. """
        app = Flask(__name__)
        app.config['TESTING'] = True
        app.config['WTF_CSRF_ENABLED'] = False
        WTF_CSRF_ENABLED = False
        app.debug = True
        self.baseURL = 'http://localhost:5000'
        return app

and when i send a post request using the client i get 400 bad request.

     def test_post_to_urlshortener(self):
        """   When we send a post we expect it to return a output
         containing the baseURL and short url """

         # monkeypatch the generate shortURL so that we know
         # the correct value to expect and perform validation
         # accordingly
         from app.models import urlshortener

          urlshortener.urlShortener.generateShortUrl = self.generate_shortURL
         data = dict(url='http://www.google.com/', submit='Shorten')

          rv = self.client.post('/',
                          data=data,
                          follow_redirects=False)
          print rv
          self.assertEqual(rv.status_code, 200)
          shorturl = self.baseURL + '/' + self.generate_shortURL()
          # print rv.data
          assert shorturl in str(rv.data)

          # cleanup so next time it works
          urlshort = urlshortener.urlShortener()
          urlshort.removeUrl(self.generate_shortURL())

The code works when i test it with browser , the only parameter that is missing from the test and the browser is csrf token.However i have disabled csrf protection using the configuration(hope so)

Any pointers to help in narrowing down the problem is welcome.

1
I don't see you calling create_app at all. Are you sure you don't use your global app?ThiefMaster
It kind of makes sense. Can you please show a small example of using it in test client to override the global appPradheep

1 Answers

1
votes

The problem seems to be that even when the csrf_token was disabled, wtf-form was raising an error as mentioned in the issue https://github.com/lepture/flask-wtf/issues/208

The worked around i did was to make the code, parse the output and extract the csrf_token . The code is as follows

    def getcsrf_value(self):

    """ get csrf token """

    rv = self.client.get('/')

    soup = BeautifulSoup(rv.data, 'html.parser')
    tag = soup.body.find('input', attrs={'name' : 'csrf_token'})
    return tag['value']