harmony_through_testing



harmony_through_testing

0 0


harmony_through_testing


On Github drewverlee / harmony_through_testing

Harmony Through Testing

about-me

  • dev @ MessageBlocks
  • @drewverlee
  • drewverlee.github.io

slides at

drewverlee.github.io/harmony_through_testing/

harmony

foundations

foundations-detail

languages

languages

languages

when working in pure functional land, mocking is trivial. Dependencies are passed as parameters, no need to set up state, certainty of correctness based on test is absolute, because of referential transparency so certainty of correctness for the particular input value you choose.

- derek verlee

languages - side effects

im_a_global = 1

def im_a_function_that_creates_some_side_effect(x):
    im_a_global += 1
    return x + 1

rv = im_a_function_that_creates_a_side_effect(5)

a side effect occurs any time we change state. A function is said to have side effects if these changes last outside the scope of the function.

Using pure functions can also allow some optimizations by changing evaluation order.The big win, however, stems from pure functions being conceptually simpler and much easier to test.

languages

m + 1 step

choosing a (imperative) language

choosing a (imperative) language

lets ask David Evans

choosing a (imperative) language

david was my first CS teacher

choosing a (imperative) language

  • languages change the way we think
    • Python ~ assignments
    • java ~ objects
  • languages provide abstractions of resources
    • hide dangerous details ~ memory locations
  • mainly we need good libraries
    • android
  • all equivalently powerful ~ could simulate programming language in another

choosing a (imperative) language

Propriety description Expressiveness how easy it to describe a computation Control how much a programmer can control machine Truthness program means what programmer wanted Safeness minimize impact of programmer mistakes.

choosing a (imperative) language

why python?

  • it has a library you want
  • you don't need lots of control
  • its expressive
  • its simplistic
  • its popular
  • your not working alongside 100's of other devs
  • ...

m + 2 step

m + 3 step

m + 4 step

Levels of testing

Scope

low - one function

  • Unit
  • Integration
  • Component Interface
  • Systems

high - entire application

testing levels

blocks

testing levels

unit

testing levels

Component interface

testing levels

Integration

testing levels

Systems

testing types

How

  • functional testing
  • smoke and sanity testing
  • fuzz testing

testing type

functional

testing process

  • Agile
  • WaterFall
  • Extreme

what about...

m + 5 step

python testing ecosystem

Python Testing Tools Taxonomy

pytest

selling points

  • plays nice with unittest
  • nose like test runner
  • less boiler-plate
  • dryer - fixtures

plays nice with unittest & test runner

less boilerplate

unitest

class TestFoo(unittest.TestCase): 

    def test_foo(self):
        self.assertEqual(foo(), "lol")

pytest

def test_foo():
    assert foo() == 'lol'

pytest-plugin-flask

conftest file

  from file_where_you_create_app import create_app

  def app():
    return create_app("Development")

testfile

def test_app(client) # client is created for you
  assert client.get(url_for("a_vew")).status_code == 200

pytest-marks

unit has some marks

@unittest.skipIf(mylib.__version__ < (1, 3),
                  "not supported in this library version")
def test_function(self):

pytest has some marks

import sys
@pytest.mark.skipif(sys.version_info < (3,3),
                    reason="requires python3.3")
def test_function():
    ...

pytest-marks-custom

pytest has custom markers

database_test = pytest.mark.DATABASE_TEST

@database_test
def test_some_part_of_db():
  ...

pytest - parametrize

import pytest
@pytest.mark.parametrize("input,expected", [
    ("3+5", 8),
    ("2+4", 6),
    ("6*9", 42),
])
def test_eval(input, expected):
    assert eval(input) == expected

code should be dry

def wet(a_list):
    a_list[0] = 1
    a_list[1] = 2
    a_list[2] = 3

    return a_list

def dry(a_list):
    for i, element in enumerate(a_list):
        a_list[i] = element += 1
    return a_list

tests should be...

def wet_test_every_element_in_a_list():
    result_list = wet(a_list)
    assert result_list[0] == 1
    assert result_list[1] == 2
    assert result_list[2] == 3

def dry_test_every_element_in_a_list():
    result_list = dry(a_list)
    for i, expected_value in enumerate([1, 2, 3]):
        assert result_list[i] == expected_value

pytest naturally damper

because of fixtures

this is a fixture

@pytest.fixture
def some_setup():
    config = "some" + " " + "setup"
    return config

this is a fixture in use

def some_test(some_setup):
    assert some_setup == "some setup"

def some_OTHER_test(some_setup):
    assert foo(some_setup) == "other setup"

we can parametrize our fixture

@pytest.fixture(params=[" with peanut butter", " with mold"])
def fixture_for_fav_food(request):
    food = fav_food()
    add_on = request.param

    food += add_on

    def happens_after_test():
        food_after = food.replace(add_on, "")
    request.addfinalizer(happens_after_test)

    return food
from fav_food import fav_food

@pytest.fixture(params=[" with peanut butter", " with mold"])
def fixture_for_fav_food(request):
    food = fav_food()
    print("BEFORE {}".format(food))
    add_on = request.param

    food += add_on
    print("WITH SETUP {}".format(food))

    def happens_after_test():
        food_after = food.replace(add_on, "")
        print("AFTER {}".format(food_after))
    request.addfinalizer(happens_after_test)

    return food

file structure

  ▾ root_project_folder/
    ▾ tests/
        conftest.py <--- were fixtures live
        test_fav_food.py <--- test file
      fav_food.py <-- module

our module

def fav_food():
    return 'apples'

our test

def test_fav_food(fixture_for_fav_food):
    assert fixture_for_fav_food == 'apples with peanut butter'

we run those test...

(testing_harmony)➜  parm_test git:(master) ✗ py.test -s

pytest fixtures advanced

how far can we take it..

pytest fixtures advanced?

im not sure

          'a'        
    +-----+   +-----+ 
    |               | 
    |               | 
    +>             <+ 

    ab              ac
    | \
    abc\
        abd

Zen of python

scoreboard

py - Beautiful is better than ugly.
un - Explicit is better than implicit.
py?- Simple is better than complex.
?? - Complex is better than complicated.
py - Flat is better than nested.
py - Sparse is better than dense.
py - Readability counts.
un - Special cases aren't special enough to break the rules.
un - Although practicality beats purity.
-- - Errors should never pass silently.
-- - Unless explicitly silenced.
-- - In the face of ambiguity, refuse the temptation to guess.
un - There should be one-- and preferably only one --obvious way to do it.
-- - Although that way may not be obvious at first unless you're Dutch.
-- - Now is better than never.
-- - Although never is often better than *right* now.
-- - If the implementation is hard to explain, it's a bad idea.
-- - If the implementation is easy to explain, it may be a good idea.
-- - Namespaces are one honking great idea -- let's do more of those!