Prerequisites
I've initially looked at my source code and Github and found that I've got few things a bit wrongly implemented (not using properly DRY principle.)
I've found also that gpxreader_test
branch should be finally merged to master.
I've found also that android-initial startup as module that as not been yet merged to master.
That why initially I needed to make prerequisites like:
1. Merging gpxreader_test
branch to master
2. Merging androidapp_submodule
branch to master
3. Fixing problem breaking DRY principle.
As you may check in this commit. Unfortunatelly this fix was in-between working with endorphine-algorithm. My only excuse is that I've followed TDD 3 principles - Make failing test, fix code for test, refactor - to be more precise I've used the "refactor" part.
4. Fixing problem with not using properly unittest module
Instead of using self.assert*
I've been using old-school pytest assert
. Thanks to this commit I've finally get rid of this old-school assertions.
First Endorphine Algorithm with TDD in mind.
1. Algorithm itself.
Lowest Point You've Been
algorithm is all about finding the lowest point in the gpx track that User have been.
If gpx track does not have lowest point, does not have points or those points are of the same elevation, then method should return None.
More comprehensive documentation is in the method documentation.
2. Test Flow for Endorphine-Algorithm for gathering 'Lowest Point You've Been'
So I've been using the TDD for this article. It was a very successful session. I've tried to practice TDD with best intentions and motivation I've found in "Uncle Bob" video about TDD.
First I've started with a failing tests, then created source-code and then refactored code for better quality and readability.
Initially I've started with this code:
@parameterized.expand([
('web/tests/example_data/fast_example_empty_points.gpx'),
])
def test_get_lowest_elevation(self, gpxfile=DEFAULT_GPXFILE_SAMPLE):
"""
Tests for get_lowest_elevation
"""
gpxreader = GPXReader(gpxfile)
if len(gpxreader.get_elevations()) <= 0:
self.assertEqual(gpxreader.get_lowest_elevation(), None)
Then I've added file called fast_example_empty_points.gpx
without any points in it -based on fast_example_trackpoints.gpx
file.
After that I've added source code that fixed failing code with :
def get_lowest_elevation(self):
if len(self.get_elevations()) <= 0:
return None
Added some small refactoring and repeated process. I didn't do all the commits for the flow, but I tried to make them as much as I could.
Final result
1. Tests.
def assert_lowest_elevation_equals(self, expected):
" Assertion for Equality of get_lowest_elevation with Expected"
self.assertEqual(self.gpxreader.get_lowest_elevation(), expected)
#pylint: disable=invalid-name
@parameterized.expand([
(DEFAULT_TESTS_EXAMPLES_PATH+'fast_example_empty_points.gpx'),
(DEFAULT_TESTS_EXAMPLES_PATH+'fast_example_points_no_elevation.gpx'),
])
def test_given_none_or_empty_elevation_return_none(self, gpxfile=DEFAULT_GPXFILE_SAMPLE):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(gpxfile)
self.assert_lowest_elevation_equals(None)
def test_given_one_available_elevation_return_none(self):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(
DEFAULT_TESTS_EXAMPLES_PATH + \
"get_lowest_elevation_one_elevation_available.gpx"
)
self.assert_lowest_elevation_equals(None)
def test_given_two_different_points_return_lowest(self):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(
DEFAULT_TESTS_EXAMPLES_PATH + \
"get_lowest_elevation_two_different_points.gpx"
)
self.assert_lowest_elevation_equals(102.0)
def test_given_two_the_same_points_return_none(self):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(
DEFAULT_TESTS_EXAMPLES_PATH + \
"get_lowest_elevation_two_the_same_points.gpx"
)
self.assert_lowest_elevation_equals(None)
def test_given_more_then_two_the_same_points_return_none(self):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(
DEFAULT_TESTS_EXAMPLES_PATH + \
"get_lowest_elevation_more_then_two_the_same_points.gpx"
)
self.assert_lowest_elevation_equals(None)
def test_given_none_and_diff_points_return_minimal_value(self):
"""
Tests for get_lowest_elevation
"""
self.gpxreader = GPXReader(
DEFAULT_TESTS_EXAMPLES_PATH + \
"get_lowest_elevation_none_and_diff_points_return_minimal_value.gpx"
)
self.assert_lowest_elevation_equals(105.0)
2. Source-code of method.
def get_lowest_elevation(self):
group_elevation = {}
for elevation in self.get_elevations():
if elevation:
group_elevation[elevation] = elevation
if len(group_elevation.keys()) == 0:
return
if len(group_elevation.keys()) == 1:
return
return min(group_elevation.keys())
Code commits done for this post:
- Fixes test for integration test of none diff point.
- Adds failing test for integration test.
- Adds fix for more then two the same points.
- Adds failing test for more_then_two_same_points.
- Fixes test for two the same points returning None.
- Fixes test of two diff-points
- Adds failing two-diff-points test.
- Refactors. Adds assert_lowest_elevation_equals.
- Adds one available elevation test.
- Refactors code for path of example file.
- Fixes pylint errors and warnings.
- Refactor code for more simplicity.
- Adds None and Empty elevations tests for get_lowest_elevation
- Fixes getlowest_elevations test.
- Fixes method can be function with self.assert*.
- Adds fix for travis issue. (#18)
- Adds androidapp as submodule (#17)
- Gpxreader tests (#16)
Tools and applications used:
- Vi/VIM
- Docker
- Tmux
- anselmos/dotfiles
- anselmos/linux-utils
LL (Lessons Learned)
1. Deploy_gh_pages travis job fails on "cannot stat.."
Issue that I've found was about travis not deploying pyreverse GitHub Page that should automatically be updated.
What I've found out, was a silly problem with make-tasks that I've recently changed for gpxreader_test branch.
Today I've finally cleaned-up this branch and merged(squashed) it to master. Then I've found out that gh_pages travis task is not working properly.
The issue itself was a bit cryptic at first hand:
cp: cannot stat `../../generated_pyreverse/*': No such file or directory
You can check this issue at Travis for this project
Solution:
I've initially thought that I forgot about adding directory of name generated_pyreverse
, but no. Thanks to simplicity of this tool and make-task I needed only few seconds to find out why this happen and what should be done.
I needed to change name of the make task used in travis to "MAKE_GH_PAGE_TASK=deploy_gh_pages_all" instead of "MAKE_GH_PAGE_TASK=deploy_gh_pages"
A kindly reminder for all users of Travis - be sure that if you have any "automatically" deployment, you do test it before running. And all changes in your deployment environment are checked before deploying :)
So , is it working now you may ask ? You may check if you ask :)
Tips & Tricks
1. Move all issues from #TODO in source code to github issues.
At first glance I've used github issues to make all "new" features/issues. Then my habits made their point and I've started using the "TODO" comments in code.
It's not a bad thing, but since I can use github issues I've found it will be useless and makes me create additional #pylint: disable=fixme
line that just hides information in code instead of showing it to me.
So I'm moving to github issues. Please if you find any type of #TODO
in my code - let me know :)
Comments
comments powered by Disqus