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:

Tools and applications used:

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 :)

Accomplished:

1. Add test-cases for business logic to GPXReader - endorphines-algorithms :)

2. Add Endorphine algorithm for 'Lowest Point You Have Been'

What's next

1. Python backend - initial REST-API.

2. Making API documentation - research for best API documentation!

3. Badge Gathering source-code and tests.



Comments

comments powered by Disqus