Created
March 5, 2018 21:58
-
-
Save hchasestevens/2723f6ae06b09e995a52fcc42d6c05e9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Property-based testing" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "from hypothesis import given, assume, example, note, settings, strategies as st\n", | |
| "from hypothesis.stateful import RuleBasedStateMachine, rule, invariant\n", | |
| "from random import randint\n", | |
| "from collections import Counter\n", | |
| "import unittest" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "## Motivation" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "Would you accept `plus`?" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def plus(x, y):\n", | |
| " if x and y:\n", | |
| " return 2\n", | |
| " return 1" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "assert plus(1, 0) == 1\n", | |
| "assert plus(0, 1) == 1\n", | |
| "assert plus(1, 1) == 2" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "def plus(x, y):\n", | |
| " if x and y:\n", | |
| " return 2\n", | |
| " return 1\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "%history 2" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def plus_v2(a, b):\n", | |
| " return a + b" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "Would you accept `plus_v2`?" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "for _ in range(1000):\n", | |
| " a = randint(-100, 100)\n", | |
| " b = randint(-100, 100)\n", | |
| " assert plus_v2(a, b) == a + b" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "def plus_v2(a, b):\n", | |
| " return a + b\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "%history 3" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "Can we test `plus_v2` without `+`?" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 8, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def associative(a, b):\n", | |
| " return plus_v2(plus_v2(a, b), 1) == plus_v2(a, plus_v2(b, 1))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 9, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def commutative(a, b):\n", | |
| " return plus_v2(a, b) == plus_v2(b, a)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 10, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def zero_is_identity(a):\n", | |
| " return plus_v2(a, 0) == a" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 11, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "for _ in range(1000):\n", | |
| " a = randint(-100, 100)\n", | |
| " b = randint(-100, 100)\n", | |
| " assert associative(a, b)\n", | |
| " assert commutative(a, b)\n", | |
| " assert zero_is_identity(a)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "Rewriting in Hypothesis" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "@given(a=st.integers(), b=st.integers())\n", | |
| "def test_plus_v2(a, b):\n", | |
| " assert associative(a, b)\n", | |
| " assert commutative(a, b)\n", | |
| " assert zero_is_identity(a)\n", | |
| " \n", | |
| "test_plus_v2()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "### Generating values" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "-30412" | |
| ] | |
| }, | |
| "execution_count": 13, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "st.integers().example()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "-1e-05" | |
| ] | |
| }, | |
| "execution_count": 14, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "st.floats().example()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "u'\\U0005423a'" | |
| ] | |
| }, | |
| "execution_count": 15, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "st.text().example()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 16, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "[False]" | |
| ] | |
| }, | |
| "execution_count": 16, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "st.lists(st.booleans()).example()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 17, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "['Context',\n", | |
| " 'Decimal',\n", | |
| " 'FloatKey',\n", | |
| " 'Fraction',\n", | |
| " 'InvalidArgument',\n", | |
| " 'LRUReusedCache',\n", | |
| " 'NOTHING',\n", | |
| " 'Nothing',\n", | |
| " 'RandomSeeder',\n", | |
| " 'ResolutionFailed',\n", | |
| " 'STRATEGY_CACHE',\n", | |
| " 'SearchStrategy',\n", | |
| " '_AVERAGE_LIST_LENGTH',\n", | |
| " '__all__',\n", | |
| " '__builtins__',\n", | |
| " '__doc__',\n", | |
| " '__file__',\n", | |
| " '__name__',\n", | |
| " '__package__',\n", | |
| " '_defer_from_type',\n", | |
| " '_strategies',\n", | |
| " 'absolute_import',\n", | |
| " 'assume',\n", | |
| " 'base_defines_strategy',\n", | |
| " 'binary',\n", | |
| " 'booleans',\n", | |
| " 'builds',\n", | |
| " 'cacheable',\n", | |
| " 'ceil',\n", | |
| " 'characters',\n", | |
| " 'check_strategy',\n", | |
| " 'check_type',\n", | |
| " 'check_valid_bound',\n", | |
| " 'check_valid_integer',\n", | |
| " 'check_valid_interval',\n", | |
| " 'check_valid_sizes',\n", | |
| " 'choices',\n", | |
| " 'complex_numbers',\n", | |
| " 'composite',\n", | |
| " 'convert_value',\n", | |
| " 'count_between_floats',\n", | |
| " 'data',\n", | |
| " 'dates',\n", | |
| " 'datetimes',\n", | |
| " 'decimals',\n", | |
| " 'deferred',\n", | |
| " 'defines_strategy',\n", | |
| " 'defines_strategy_with_reusable_values',\n", | |
| " 'dictionaries',\n", | |
| " 'division',\n", | |
| " 'dt',\n", | |
| " 'enum',\n", | |
| " 'fixed_dictionaries',\n", | |
| " 'float_to_int',\n", | |
| " 'floats',\n", | |
| " 'floor',\n", | |
| " 'fractions',\n", | |
| " 'from_regex',\n", | |
| " 'from_type',\n", | |
| " 'frozensets',\n", | |
| " 'gcd',\n", | |
| " 'get_type_hints',\n", | |
| " 'getfullargspec',\n", | |
| " 'hrange',\n", | |
| " 'implements_iterator',\n", | |
| " 'infer',\n", | |
| " 'int_to_float',\n", | |
| " 'integers',\n", | |
| " 'is_negative',\n", | |
| " 'isclass',\n", | |
| " 'isfunction',\n", | |
| " 'iterables',\n", | |
| " 'just',\n", | |
| " 'lists',\n", | |
| " 'math',\n", | |
| " 'none',\n", | |
| " 'not_set',\n", | |
| " 'note_deprecation',\n", | |
| " 'nothing',\n", | |
| " 'one_of',\n", | |
| " 'operator',\n", | |
| " 'permutations',\n", | |
| " 'print_function',\n", | |
| " 'proxies',\n", | |
| " 'random_module',\n", | |
| " 'randoms',\n", | |
| " 'recursive',\n", | |
| " 'reduce',\n", | |
| " 'register_type_strategy',\n", | |
| " 'renamed_arguments',\n", | |
| " 'required_args',\n", | |
| " 'runner',\n", | |
| " 'sampled_from',\n", | |
| " 'sets',\n", | |
| " 'shared',\n", | |
| " 'streaming',\n", | |
| " 'text',\n", | |
| " 'text_type',\n", | |
| " 'timedeltas',\n", | |
| " 'times',\n", | |
| " 'try_convert',\n", | |
| " 'tuples',\n", | |
| " 'uuids']" | |
| ] | |
| }, | |
| "execution_count": 17, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "dir(st)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "### Property-based testing patterns\n", | |
| "\n", | |
| "* \"Doesn't blow up\"\n", | |
| "* Encode/decode\n", | |
| "* Idempotence\n", | |
| "* Oracle" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "celltoolbar": "Slideshow", | |
| "kernelspec": { | |
| "display_name": "Python 2", | |
| "language": "python", | |
| "name": "python2" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 2 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython2", | |
| "version": "2.7.14" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 1 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment