2

Consider this code:

def get_some_text():
    return _(u"We need this text here")

What is the best way to write a unit test that makes sure the function returns this - referenced and translated by Babel - string?

This naive code would not contain a reference - so this are actually a different "Babel strings":

def test_get_some_text(self):
    self.assertEqual(get_some_text(), _(u"We need this text here"))
desertnaut
  • 57,590
  • 26
  • 140
  • 166
Thorben Croisé
  • 12,407
  • 8
  • 39
  • 50
  • I'm not sure what you mean by "somehow referenced", could you explain? Also, what does the underscore do (is it a function defined elsewhere)? – Jomel Imperio May 11 '15 at 08:21
  • I edited the question a bit. "_" is the babel way of marking a string for translation: http://babel.pocoo.org/docs/messages/ – Thorben Croisé May 11 '15 at 08:28

1 Answers1

2

If you're using flask-babel, don't mind using mocks, and you're only testing what _ returns (i.e. get_some_text doesn't do any additional transformations on the result of _), then you can mock the return value of _ and test that you get what you expect:

import mock


@mock.patch('gettext.ugettext')
def test_get_some_text(self, mock_ugettext):
  mock_ugettext.return_value = u'Hello World'

  self.assertEqual(get_some_text(), u'Hello World')

We know that _ calls ugettext from here, and if we drop an import ipdb; ipdb.set_trace() line right before, we can hop into a python shell, call get_some_text, and use this answer to find the import path of ugettext, which turns out to be gettext.ugettext.

If you're only using babel, and you know the path to your translations directory, you might be able to make your own translations just for testing:

import os
import shutil

import polib    


os_locale = ''
translations_directory = '/absolute/path/to/your/translations'
# choose a locale that isn't already in translations_directory
test_locale = 'en_GB'

def setUp(self):
    mo_file_path = os.path.join(
        translations_directory,
        test_locale,
        'LC_MESSAGES',
        'messages.mo'
    )
    mo = polib.MOFile()
    entry = polib.MOEntry(
        msgid=u'We need this text here',
        msgstr='My favourite colour is grey'
    )
    mo.append(entry)
    mo.save(mo_file_path)

    # modify our locale for the duration of this test
    os_locale = os.environ.pop('LANG', 'en')
    os.environ['LANG'] = test_locale

def tearDown(self):
    # restore our locale
    os.environ['LANG'] = os_locale
    shutil.rmtree(os.path.join(translations_directory, test_locale))

def test_get_some_text(self):
    self.assertEqual(get_some_text(), u'My favourite colour is grey')
Community
  • 1
  • 1
cswen17
  • 21
  • 3
  • Since this was written, `_` has been modified and calls `flask_babel.gettext`. Now you should use `@mock.patch("flask_babel.gettext")` instead. – Dag Høidahl Sep 23 '21 at 11:57