Git and TDD

Kastoria TEI

Gérard Rozsavolgyi

IUT Orléans

IUT Orléans, France

roza@univ-orleans.fr

Python Intro

Version Control Systems: Git

Agile, Tests and TDD

  • Plan:

    • Version control systems
    • Git, first steps
    • Agile and TDD
    • Tests
    • TDD demo

Problem 1

Keep track of code modifications day after day … and revert to a previous version if needed

Problem 2

  • share a developpement between several persons
  • allow remote accesses from various platforms
  • quickly find the origin of a Bug in case of regression

Problem 3

How to deal with distributions ?

several versions can coexist ( developpement branches, beta branches, production branches )

Complexity

Several branches to manage simultaneously …

Or

chrome branches…

A version control system

  • Acts on a file tree
  • Allows to pool and share a development
  • Stores any evolution of the source code

Adds a new dimension to the file system: time

2 models

  • centralized
  • decentralized

Centralized 👹

  • SVN like
  • a single reference repository
  • need of synchronization
  • need of a server
  • frequent conflicts …

Decentralized 🔆

  • several repositories for the same software
  • everyone can work at their own pace
  • synchronized or not with others

Advantages of decentralized systems ⭐️

  • not dependent on a specific machine
  • work offline
  • progressive and “lean” participation in a project
    • access to the code
    • proposed contribution
    • become an active contributor if accepted

main repository

  • contains the delivered versions of a project
  • A repository or repo is a central location where are stored:
    • file version history
    • logs
    • dates, authors, tags, etc.

Repo 📂

A repository appears from the outside as a file system composed of directories in which we can navigate, read and write according to the permissions granted.

Master (or Trunck in SVN) 🌳

  • main version
  • from it, we can create branches

Branches 🌵

  • a “secondary” development is initiated
  • to develop a new feature
  • to fix a bug

Destiny of a branch

  • A branch can either be merged again into the “master”
  • disappear
  • or give rise to a new program. We speak then of fork

Checkout

  • is to get a copy of the existing files in a repository
  • The result is a working copy
  • Under git it also consists in choosing his branch (master, dev, etc.)

Commit ⛳️

    git commit -m "added a wonderful new feature"

or if you want to add at the same time all modifications on existing files :

    git commit -am "added a wonderful new feature"

Commit ⛳️

  • Update local copy and then remote repository
  • A new revision is created
  • the working copy must match the last version of the repository
  • a message is associated to the commit
  • possibly a tag

Merge

  • Merging 2 branches
  • Merging a branch with the master

merge illustrated

Commits, branches and merge

Visualize git commits and branches

Conflicts 🤼‍♂️

  • some changes may be contradictory
  • for example, when two people made different changes to the same part of a file …
  • we must then resolve this conflict!

Diff

  • Displays the difference between two versions of a file
  • diff command (or kdiff for linux)

mergetools

For more complicated cases:

  • kdiff3
  • opendiff

Git

  • Most used
  • created by Linus Torvalds to manage the development of the Linux kernel
  • hundreds of contributors

Linux Kernel contributions

Later

Git

git xkcd

base commands

alan> git config --global user.name "Alan Turing "
alan> git config --global user.email "alan@teiwm.gr"
alan> git config --global core.editor code
alan> git config -l

git help

Documentation

bob> git --help
bob> git help -a
bob> git help init

working with git

  git init
  • a .git folder appears

  • To see its contents :

    tree .git

git add

To add everything in the folder:

  git add .

To add a specific file:

  git add myfile

commit

  • atomic operation for the repo
  • not too small, not too big
  • single contribution
  • don’t fix 3 bugs and develop 2 new features in the same commit !!

rm

  • don’t rm a versioned file !

  • you can remove it under git control:

      git rm myfile

First demo

  • create a toy project
  • add a Readme.md
  • commit
  • change something
  • use git diff to show file differences
  • commit new version
  • git status, git log, etc.

Use a remote repository

  • Version a local directory with git
  • make a few commits
  • to publish your work:
  git remote add origin https://gitlab.com/bob/myproject.git

publish your work

    git push -u origin master

and when you’ll have new content to publish, just do :

    git push

git status

Always do a git status to check :

  • if you have changes to commit
  • on which branch you are working
  • if you miss some commits from a remote
  • or the opposite: Your branch is ahead of 'origin/master' by 3 commits.

update (pull) 🔄

git pull

The update synchronizes the local working copy with the remote repository

git pull 🆕

  • retrieves the latest version of the remote repo files
  • on this occasion, version conflicts can appear :)

git workflow

git stages

Famous places to host your git repos

Github, Gitlab, etc.

different hostings

  • Github has now free private repos. Bought by Microsoft. See
  • Gitlab and bitbucket always had private repos.
  • You can download and install your own gitlab or Gogs

ignore somme files

  • add and commit a new .gitignore file
  • containing a list of files or extensions you want to ignore (avoid versionning)
*.o
__pycache__
*.class
*~

Add other remotes

for example if you work with Alice:

  git remote add https://gitlab.com/alice/newproject.git

and list all remotes:

  git remote -v

Create and use a branch

  git branch db-integration
  git checkout db-integration

or in one line:

  git checkout -b db-integration

Contribute to a project

  1. Choose a nice project (nodejs, ruby on rails, d3js, etc.) on github or gitlab
  2. fork it on github
  3. clone your fork in your workspace
  4. choose a submited bug or a simple new feature needed See for example NodeJS Github repo

Contribute

  1. create a branch to code the feature, test it
  2. publish it on your repo
  3. Submit a Pull Request or PR (Github) Submit a Merge Request or MR (Gitlab)
  4. Wait for the verdict. If not accepted, go back to 5

Rejection motives 😭

  • branch does not merge
  • Code style, lack of comments
  • missing or failing tests
  • needs rebase

Continuous integration

  • some tests or programs can be automatically launched when new commits are pushed
  • gitlab-ci.yml in Gitlab
  • similar to Dockerfiles
  • examples at the end

TDD - Agile methods

  • Test-Driven Development
  • Kent Beck 2003
  • first concepts of extreme programming
  • part of “Agile methods”

Agile methods

  • Agile Methods are setting up new ways of organisation
  • Not only in Computer Science
  • Car industry, logistics, etc.

Best known agile methods

  • Pair Programming
  • Test Driven Development
  • Scrum
    • Scrum Master
    • Product Owner
    • Sprints
    • StandUp meetings

Standup Meetings

IT daily standup meetingAn other standup meeting

purpose of these meetings

  • Make a feedback
  • Plan and organise near future
  • Be in an “active” position

Backlogs (Todo lists)

A nice backlog

Overloaded backlog

An ugly backlog

Scrum methodology

Scrum elements

Scrum elements

  • Corner stones :
    • Backlog items
    • Tests
    • TDD and versionning
  • Groups:
    • Typicaly 4-5 people
    • but some projects involve hundreds of people (linux Kernel, OSes, etc.)

Corner stone: Tests

  • Different kinds of tests
  • examples
  • Why TDD ?

Different kinds of tests

In CS, a test is a partial verification procedure of a system

There is a huge diversity of tests, we will focus on the 3 main categories

Main types of tests

  • unit tests : that apply on method or function isolated from the rest of the system. (ie a function add(integer1, integer2) )
  • integration tests : like unit tests, but not isolated from the rest of the system
  • functionnal tests : a test on a feature (for example in a web application offering a calculator, to be able to add two integers)

examples

  • to test a function, we provide a list of (input / output)
  • to test a functionality, we can describe what is the expected behavior described by a User Story
  • See TDD with Python for many functional tests examplessezez

Examples for a calculus app

  • unit test: a call to add(1,2) returns 3
  • integration test : compute("1 + 2") returns 3. (See the difference ??)
  • functional test : if i type 1+2 in a Web form, and then press the Submit button, i will get 3 displayed in a green box.

a movie management app unit test

  • we make a call to a function searchActor(“bruce”,DB)
  • where DB is a mockup DataBase created with a unique movie without any Bruce
  • it should return null

a movie management app integration test

  • if we invoke add(new Film("Star Wars"))
  • then search movies containing “Star”
  • we should (at least) get “Star Wars” as result

a movie management app functional test

On my client home page:

  • When opening the home page, we see a search bar
  • we type “Star” and ENTER in this search Bar
  • We get the list of all Star Wars movies displayed in a green Box below

Why tests ?

  • When you code a function, you (almost) always test it, at least once, at least for one specific input …
  • but not extensively nor in a rigorous way
  • launch the program, see what happens on a few inputs
  • Why are you doing so ?

Why ?

  • you want to improve bug detection
  • you want to specify what you expect
  • when you write the function, you are thinking consciously or not to some example of function calls.
  • you are doing unit tests !!

User story

  • when you ask a client what an app should do, he might start telling you a story like: “When I come to the home page, I want to connect with my login and passwd and then consult my tasks for the day, …”
  • he is describing a functional test

Test Driven Development

  • if we formalize the idea of thinking first to input/output examples before coding
  • we get to the TDD :
    • define tests
    • then we code

Obey the testing Goat 🐏

TDD Mantra

TDD steps

  1. Choose an item in the backlog
  2. Create a simple test to check the expected functionnality
  3. Write the test
  4. Launch the test : check that it fails. Commit !
  5. Write the minimal code to pass the test
  6. Test it. if it’s green, commit !
  7. Refactor
  8. Test the refactoring : launch again the tests. Commit !
  9. Keep going (go back to step 1.) !

demo 2

Let’s start with a backlog of features to implement and focus on unit tests !

Our Backlog: 2D-Points

  • Create a Point
  • get x-coordinate
  • get y-coordinate
  • Compare two points for equality

Don’t forget the mantra

TDD cycle

Some tests

def test_point_creation():
    p = point(22,7)

def test_access_x_and_y():
    assert 22 == getx(p)
    assert 7 == gety(p)

commit !

First implementation of point

def point(x,y):
    return [x,y]

def getx(p):
    return p[0]

def gety(p):
    return p[1]

test. Commit !

Point refactoring as Object

class point:
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def getx(self):
        return self.x

    def gety(self):
        return self.y

Refactor test

  • Change the test to match new API
  • test
  • commit !

Testing equality of points

def test_equality():
    p1 = point(1 ,3)
    p2 = point(1 ,3)
    p3 = point(2 ,5)
    assert p1 == p1
    assert p1 == p2
    assert p2 == p1
    assert p1 != p3

new backlog

  • Create a rectangle object with 4 parmeters:
    • x,y : coords of the lower left corner of the rectangle
    • w,h: width and height of the rectangle
  • get x,y,x,h
  • get the position of rectangle’s center
  • get the rectangle’s area

first rectangle test

def test_creation():
    r = rectangle(22,7,300,250)
    assert 22 == r.getx()
    assert 7 == r.gety()
    assert 300 == r.getw()
    assert 250 == r.geth()

Implementation

etc.

Try some katas

String Calculator

Quality of tests

  • The tests must be orthogonal (independent of each other)
  • few, direct, stable, fast
  • should not concern private methods,
  • each behavior must be tested in one and only one test
  • do not make unnecessary assumptions (okham razor)
  • have good naming convention in your tests: a test name is an understandable phrase for every body (even non-programmers)

be careful 🚫

  • code architecture must allow unit tests
  • If it is not the case, it is because there is a problem of design in your code … (for example a function doing several things at the same time)
  • Bad tests can be more problematic than no test at all …

Automating tests

All languages ​​have developed unit test modules/libs

  • phpUnit for PHP
  • JUnit for Java
  • pytest or unnitest in Python
  • GoogleTest or Boost in C++