Creating a URL Shortener with Flask - Part 4
17 Dec 2015In this part 4 , i will discuss more on additional 2 tools which will help us keep the code consistent and also figure out ares of improvement.
Code coverage
Code coverage is one of the oldest tools available for measuring the amount of test coverage. Earlier that code coverage was performed with manual test cases but with automation of unit test becoming a norm now a days , the test coverage can be run regularly.
-
Python support of code coverage is done with a tool called
coverage
. It can be installed as belowpip install coverage
-
Now that we have all the tests that are automated we can easily run the code coverage as below
$coverage run --source app -m unittest discover ------------------------------- Ran 11 tests in 0.173s OK
The above code runs all the unit tests and stores the coverage in a file called
.coverage
in the directory you ran the command. -
To see the report , we should see the coverage report command as
$ coverage report -m Name Stmts Miss Cover Missing --------------------------------------------------------------- app/__init__.py 3 0 100% app/models/MongodbHandler.py 9 0 100% app/models/__init__.py 0 0 100% app/models/test_urlShortener.py 55 1 98% 90 app/models/urlshortener.py 32 4 88% 32-33, 43-45 app/views.py 27 1 96% 48 --------------------------------------------------------------- TOTAL 126 6 95%
The output clearly points out the missing lines in the coverage .
-
Lets make it easy to run the coverage by putting all the coverage in a make file . Lets first create a new branch called
addCoverageSupport
to track all our coverage related changes.git branch addCoverageSupport git checkout addCoverageSupport
-
Though we can run it manually every time, it would be better if we could make the coverage also run automatically as part of our automatic build process(travis).To do this we have to use a online tool called
coveralls
. -
Sign up and create a new account for you and enable the repo on the coverall. Doing all this should be straight forward.
-
Install
coverall
for doing the code coverage as belowpip install coveralls
-
Add the
coveralls
to.travis.yml
for running code coverage as below# command to run tests script: coverage run --source=app -m unittest discover after_success: coveralls
-
Now update the
requirement.txt
and push the changes to the github so that it runs on travispip freeze > requirement.txt git add . git commit -m "Added coveralls support" git push origin addCoverageSupport
-
When travis runs and is successful, it pushes all the code coverage report and the output should be somthing similar to below.
From the above, its clear that we have a code coverage of 94%, we will look more into how to get to a code coverage of 100%
-
Merge the changes into the master and we will create a new branch for making the code coverage to 100%
git checkout master git merge addCoverageSupport
-
Push the changes to github using
git push master origin
Improve code Coverage
Now lets work on to improve the code coverage to make sure we cover all the cases, by looking at the profile output from the coveralls.
-
Lets first create a branch to do all the changes related to code coverage improvement.
git checkout -b improveCode
-
The code has no coverage for the case where we try to access a shortURL that is not available. In this case , the url shortener must return 404 not found. So lets add a functional test to improve code coverage in
testing/test_basicsite.py
# try to access a invalid shorturl and the code # must return error code 404 not found def test_get_invalidShortUrl(self): # invalid shortUrl shorturl = self.baseURL + '/' + '112111111' rv = self.client.get(shorturl) self.assertEqual(rv.status_code, 404)
-
The code has no coverage for case where the model fails to perform operation like save. In case of error trying to create a shortURL ,we should return a back to the index page and with possibly a flash messsage. For time being we will only check if the page returns back to the index.html
# the case where we send a request to shorten the url and for # whatever reason , the code shortened url is not created def test_post_to_urlShortener_fail_in_model(self): # monkey patch the code to make sure that the saveUrl returns # false so we can check the return value. from app.models import urlshortener beforepatch = urlshortener.urlShortener.saveUrl urlshortener.urlShortener.saveUrl = self.stub_saveURL_returns_false post_data = {'url': 'http://www.google.com/'} rv = self.client.post('/urlshorten', data=post_data, follow_redirects=False) self.assertEqual(rv.status_code, 200) #cleanup urlshortener.urlShortener.saveUrl = beforepatch
With this we improve the code coverage to 96%. We will stop at this as we have some more code at model level to perform and we will look at improving the coverage more when we make changes.