Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Be good to yourself. Write testable code.

Adora Nwodo
November 16, 2019

Be good to yourself. Write testable code.

Adora Nwodo

November 16, 2019
Tweet

More Decks by Adora Nwodo

Other Decks in Programming

Transcript

  1. Be good to yourself.
    Write testable code.

    View Slide

  2. View Slide

  3. SUaaS
    Suffering as a Service

    View Slide

  4. View Slide

  5. View Slide

  6. Hi, I’m Adora!
    Software Engineer, Microsoft Mixed Reality
    Writer & Youtuber, AdoraHack
    Twitter: @theadoranwodo

    View Slide

  7. Unit tests run against an individual unit of software
    @theadoranwodo

    View Slide

  8. This means we should learn to write code
    so that we can test each unit of software
    @theadoranwodo

    View Slide

  9. How do we
    write testable code?
    @theadoranwodo

    View Slide

  10. Question: How do we write testable code?
    Answer: SOLID Principles
    @theadoranwodo

    View Slide

  11. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    @theadoranwodo

    View Slide

  12. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    @theadoranwodo
    interface Input {
    Data fetch();
    }
    interface Output {
    DataObject convertToObject
    (String result);
    }
    interface ProcessManager {
    String process(Data data);
    }
    class ProcessJob {
    // ...
    ProcessJob
    (Input input, Output output, ProcessManager
    processManager
    ) {
    this.input = input;
    this.output = output;
    this.processManager = processManager;
    }
    DataOutput process() {
    Data data = this.input.get();
    String result = this.processManager
    .process(data);
    return this.output.convertToObject(result);
    }
    }

    View Slide

  13. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    @theadoranwodo

    View Slide

  14. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    @theadoranwodo
    Open to extensions and closed
    to modifications
    _______________________________
    Practice coding to abstractions,
    rather than core
    implementations

    View Slide

  15. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    @theadoranwodo

    View Slide

  16. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    @theadoranwodo
    Functions that use references to
    base classes must be able to use
    objects of derived classes
    without knowing it.

    View Slide

  17. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    @theadoranwodo

    View Slide

  18. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    @theadoranwodo
    Don’t make clients depend on
    methods they don’t use

    View Slide

  19. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    @theadoranwodo
    interface Vehicle {
    void brake();
    void truttle();
    void clutchDown ();
    }
    class MyPrado implements Vehicle{
    void brake(){
    // code here
    }
    void clutchDown (){
    /* I don’t need this method
    but I have to implement it by force
    so I’d just throw an exception here */
    throw new UnsupportedException();
    }
    void truttle(){
    // code here
    }
    }
    Don’t do this

    View Slide

  20. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    @theadoranwodo
    interface Vehicle {
    void brake();
    void truttle ();
    }
    interface Manual {
    void clutchDown ();
    }
    class MyPrado implements Vehicle {
    void brake(){
    // code here
    }
    void truttle (){
    // code here
    }
    }
    class MyMaserati implements Vehicle, Manual {
    void brake(){
    // code here
    }
    void clutchDown (){
    // code here
    }
    void truttle (){
    // code here
    }
    }
    Do this

    View Slide

  21. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    Dependency Inversion Principle
    @theadoranwodo

    View Slide

  22. Question: How do we write testable code?
    Answer: SOLID Principles
    Single Responsibility Principle
    Open/Closed Principle
    Liskov Substitution Principle
    Interface Segregation Principle
    Dependency Inversion Principle
    @theadoranwodo
    High level modules should not depend
    on low level modules, both should
    depend on abstractions.
    ________________________________________
    Abstractions should not depend on
    details but details should depend on
    abstractions

    View Slide

  23. @theadoranwodo
    interface Input {
    Data fetch();
    }
    interface Output {
    DataObject convert(String result);
    }
    interface ProcessManager {
    String process(Data data);
    }
    class ProcessJob {
    // ...
    ProcessJob
    (Input input, Output output, ProcessManager
    processManager
    ) {
    this.input = input;
    this.output = output;
    this.processManager = processManager;
    }
    DataOutput process() {
    Data data = this.input.get();
    String result = this.processManager
    .process(data);
    return this.output.convert(result);
    }
    }
    ProcessJob
    Input ProcessManager
    Output
    DatabaseInput CustomProcessManager
    JSONOutput
    Interface Interface Interface
    Implementation Implementation
    Implementation
    uses uses uses
    implements implements implements

    View Slide

  24. What else can we do to make sure
    our code is testable?
    @theadoranwodo

    View Slide

  25. @theadoranwodo
    Dependency
    Injection.
    - Loosely coupled code
    - Ask for what you need, don’t look or try to create.
    - Each unit should have limited knowledge about other
    units

    View Slide

  26. @theadoranwodo
    Make sure object
    creation logic & app
    logic are different
    Your application should have two types of classes:
    - Factories for creating new objects.
    - Application classes that contain the business logic for
    your app.

    View Slide

  27. @theadoranwodo
    Respect your
    constructors
    Don’t do work in your constructors
    class Person{
    private int buildCode;
    Person(BuilderHelper helper, int seed){
    buildCode = helper.getCodeBuilder ()
    . generateCode (seed)
    . build();
    }
    }
    Don’t do this

    View Slide

  28. @theadoranwodo
    Respect your
    constructors
    Don’t do work in your constructors
    class Person{
    private int buildCode;
    Person(int buildCode){
    this.buildCode = buildCode;
    }
    }
    Do this instead

    View Slide

  29. @theadoranwodo
    Less static methods
    Avoid static methods as much as possible:
    - They are hard to test.
    - They are hard to mock.

    View Slide

  30. Code samples
    @theadoranwodo

    View Slide

  31. Let’s see a common bad real life example
    @theadoranwodo

    View Slide

  32. class Hotel
    {
    public Room getRoom(int roomId)
    {
    RoomDbClient client = RoomDbClientProvider
    .getClient();
    Room room = null;
    try {
    room = client.getRoomRecord(roomId);
    } catch(DatabaseException ex){
    ex.printStackTrace
    ();
    }
    }
    }
    class RoomDbClient implements DbClient
    {
    // more code above …
    public Room getRoomRecord(int id)
    {
    DbHelper helper = new DbHelper(“room”);
    //...
    Room room = helper.read(id);
    return room;
    //...
    }
    }
    @theadoranwodo

    View Slide

  33. class Hotel
    {
    public Room getRoom(int roomId)
    {
    RoomDbClient client = RoomDbClientProvider
    .getClient();
    Room room = null;
    try {
    room = client.getRoomRecord(roomId);
    } catch(DatabaseException ex){
    ex.printStackTrace
    ();
    }
    }
    }
    class RoomDbClient implements DbClient
    {
    // more code above …
    public Room getRoomRecord(int id)
    {
    DbHelper helper = new DbHelper(“room”);
    //...
    Room room = helper.read(id);
    return room;
    //...
    }
    }
    @theadoranwodo

    View Slide

  34. class Hotel
    {
    public Room getRoom(int roomId)
    {
    RoomDbClient client = RoomDbClientProvider
    .getClient();
    Room room = null;
    try {
    room = client.getRoomRecord(roomId);
    } catch(DatabaseException ex){
    ex.printStackTrace
    ();
    }
    }
    }
    class RoomDbClient implements DbClient
    {
    // more code above …
    public Room getRoomRecord(int id)
    {
    DbHelper helper = new DbHelper(“room”);
    //...
    Room room = helper.read(id);
    return room;
    //...
    }
    }
    @theadoranwodo

    View Slide

  35. class Hotel
    {
    public Room getRoom(int roomId)
    {
    RoomDbClient client = RoomDbClientProvider
    .getClient();
    Room room = null;
    try {
    room = client.getRoomRecord(roomId);
    } catch(DatabaseException ex){
    ex.printStackTrace
    ();
    }
    }
    }
    class RoomDbClient implements DbClient
    {
    // more code above …
    public Room getRoomRecord(int id)
    {
    DbHelper helper = new DbHelper(“room”);
    //...
    Room room = helper.read(id);
    return room;
    //...
    }
    }
    @theadoranwodo

    View Slide

  36. Now, let’s see a basic foobar example
    @theadoranwodo

    View Slide

  37. class Foo
    {
    public Bar getBar(int barId)
    {
    Rabbit rabbit = new Rabbit();
    Animal animal = new Animal();
    Bar bar = animal.doSomething (barId, rabbit);
    return bar;
    }
    }
    @theadoranwodo

    View Slide

  38. class Foo
    {
    public Bar getBar(int barId)
    {
    Rabbit rabbit = new Rabbit();
    Animal animal = new Animal();
    Bar bar = animal.doSomething (barId, rabbit);
    return bar;
    }
    }
    @theadoranwodo

    View Slide

  39. class Foo
    {
    private final Rabbit rabbit;
    private final Animal animal;
    public Foo(RabbitFactory rabbitFactory, AnimalFactory animalFactory ){
    this.rabbit = rabbitFactory .Create();
    this.animal = animalFactory .Create();
    }
    // more code …
    public Bar getBar(int barId)
    {
    Bar bar = animal.doSomething (barId, rabbit );
    return bar;
    }
    }
    @theadoranwodo

    View Slide

  40. This is Jennifer.
    Jennifer writes testable code.
    Her team members love her because it’s easy to understand and test her code.
    Jennifer is a great Engineer.
    Be like Jennifer.
    @theadoranwodo

    View Slide

  41. Thank you!
    www.adoranwodo.com
    @theadoranwodo

    View Slide