Efficient TDD in RUST

Thomas WICKHAM

@mackwic

RustFest 2017

Zurich

A bit about me...

Open Source by night

@mackwic

@mackwic

mackwic@gmail.com

PARIS - RABAT - LAUSANNE - SAO PAULO - SYDNEY

Slides
Links

are online
in the notes

T
D
D

ests
riven
evelopment

Why do we test first ?

Why

first

Easier to write

Easier

Test the intent

intent

Helps my

design

Test my understanding

understanding

Executable

specification

I test first because:

  • It's easier to write
  • I want to test the intent 
  • It helps me in my design
  • It challenges my understanding
  • It is an executable specification

ROI of TDD links in appendices

if you need to argue with your boss...

How does it works ?

Red

Green
Refactor

RED

GREEN

REFACTOR

And again...

How to choose the next test ?

A quick example

RED: To make a function, call it

#[test]
fn it_exists() {
    Divisor::divide()
}
error[E0599]: no function or associated item named `divide` found for type `Divisor` in the current scope

GREEN: create the function

impl Divisor {
    fn divide() {}
}
running 1 test
test it_exists ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

REFACTOR: nothing to do

RED: put a simple error case

#[test]
fn it_err_when_zero_is_given() {
    // arrange
    // act
    let res = Divisor::divide(12, 0); // division by 0
    // assert
    assert!(res.is_err())
}

GREEN: adapt the signature

impl Divisor {
    fn divide(numerator: u32, denominator: u32)
    -> Result<(), ()> {
        Err(())
    }
}

REFACTOR: nothing to do

Rince and Repeat

  • The next test:  a muscle to train

  • Hard because it forces to slow down

  • You don't need anything. Start now

General tips and remarks

There is no NULL and it helps us

error_chain is really nice

Where do I put my tests ?

Unit tests in `_test` modules

Where do I put my tests ?

Integration tests in `tests/` directory

Where do I put my tests ?

Functional tests in `examples/` directory

and Documentation exemples

Group tests of one method

in a module

mod task {
    pub use parser::task::*;

    mod resolve_include {
        pub use super::*;

        #[test]
        fn it_exists() {...}

        #[test]
        fn it_returns_a_full_path() {...}

        #[test]
        fn include_is_an_error_when_reading_from_stdin() {...}
    }

    mod has_name {...}

    mod is_templated {...}
}

The super neat `pub use super::*`

mod task {
    pub use parser::task::*;

    mod resolve_include {
        pub use super::*;

        #[test]
        fn it_exists() {...}

        #[test]
        fn it_returns_a_full_path() {...}

        #[test]
        fn include_is_an_error_when_reading_from_stdin() {...}
    }

    mod has_name {...}

    mod is_templated {...}
}

Think readability:

Please Do Repeat Yourself in your tests

A failing test should be a complete and explicit bug report

Closing thoughts

If you need a

SetUp/TearDown it's  most probably an Integration Test

Want Culture Code translated ?

LAUSANNE:

ch-info@octo.com (or jglorieux@octo.com)

 

PARIS:

recrutement@octo.com

(or twickham@octo.com)

 

APPENDICES

ROI of TDD links

Efficient TDD in Rust

By Thomas Wickham

Efficient TDD in Rust

  • 2,951