dtonhofer

dtonhofer

Functional Programming in Java, Second Edition: JUnit code improvements for Chapter 11, pages 181 ff "Refactoring the Traditional for loop"

Suggestions for some JUnit test improvements in Refactoring the Traditional “for” loop p 181 ff

Below code for testing the original/classical “factorial” and the stream-based “factorial” .

The following changes have been made:

  • The Factorial class has been given a constructor printing something when it is called (just for fun)
  • Creating BigInteger instances is annoying, so we use the bigOf() static method to create them.
  • The computeFactorial() function throws an exception if negative values are passsed in, as it should.
  • In order to compare an existing class’ behaviour against the behaviour of newly implemented class (supposed to be a drop-in replacement), we need to identify the methods relevant to the test, factor them out into a new interface, and have the new and old classes implement that interface (in the real world, fixing the old code in that way may not always be possible though). Proceeding according to this recipe allows us to use the same test code to exercise the old and new classes with the same test harness - no test code duplication is needed for the two separate classes.
  • There is no valid reason to have a @BeforeEach method as shown in the book, as that method is only called once even in the presence of assertAll(). It is cleaner to move the initialization of Factorialinto the individual @Test methods to keep everything local.
  • Testing of some “failure cases” (here, one case) has been added. Those are often forgotten in real life.
package chapter11;

import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.util.stream.LongStream;

import static org.junit.jupiter.api.Assertions.*;

public class TraditionalForLoopTest {

    interface Factorial {

        BigInteger compute(long upTo);

    }

    static class FactorialBefore implements Factorial {

        public FactorialBefore() {
            System.out.println("Created " + getClass().getName());
        }

        public BigInteger compute(long upTo) {
            if (upTo < 0) {
                throw new IllegalArgumentException("The passed values is < 0: " + upTo);
            }
            BigInteger result = BigInteger.ONE;
            for (int i = 1; i <= upTo; i++) {
                result = result.multiply(BigInteger.valueOf(i));
            }
            return result;
        }

    }

    static class FactorialAfter implements Factorial {

        public FactorialAfter() {
            System.out.println("Created " + getClass().getName());
        }

        public BigInteger compute(long upTo) {
            if (upTo < 0) {
                throw new IllegalArgumentException("The passed values is < 0: " + upTo);
            }
            return LongStream.rangeClosed(1, upTo)
                    .mapToObj(BigInteger::valueOf)
                    .reduce(BigInteger.ONE, BigInteger::multiply);
        }

    }

    private static BigInteger bigOf(long x) {
        return BigInteger.valueOf(x);
    }

    private static void commonFactorialTests(final Factorial factorial) {
        assertAll(
                () -> assertEquals(bigOf(1), factorial.compute(0)),
                () -> assertEquals(bigOf(1), factorial.compute(1)),
                () -> assertEquals(bigOf(2), factorial.compute(2)),
                () -> assertEquals(bigOf(6), factorial.compute(3)),
                () -> assertEquals(bigOf(120), factorial.compute(5)),
                () -> assertThrows(IllegalArgumentException.class, () -> factorial.compute(-1))
        );
    }

    @Test
    void factorialBefore() {
        commonFactorialTests(new FactorialBefore());
    }

    @Test
    void factorialAfter() {
        commonFactorialTests(new FactorialAfter());
    }

}

Where Next?

Popular Pragmatic Bookshelf topics Top

jimschubert
In Chapter 3, the source for index introduces Config on page 31, followed by more code including tests; Config isn’t introduced until pag...
New
raul
Hi Travis! Thank you for the cool book! :slight_smile: I made a list of issues and thought I could post them chapter by chapter. I’m rev...
New
Mmm
Hi, build fails on: bracket-lib = “~0.8.1” when running on Mac Mini M1 Rust version 1.5.0: Compiling winit v0.22.2 error[E0308]: mi...
New
raul
Page 28: It implements io.ReaderAt on the store type. Sorry if it’s a dumb question but was the io.ReaderAt supposed to be io.ReadAt? ...
New
AleksandrKudashkin
On the page xv there is an instruction to run bin/setup from the main folder. I downloaded the source code today (12/03/21) and can’t see...
New
Chrichton
Dear Sophie. I tried to do the “Authorization” exercise and have two questions: When trying to plug in an email-service, I found the ...
New
brian-m-ops
#book-python-testing-with-pytest-second-edition Hi. Thanks for writing the book. I am just learning so this might just of been an issue ...
New
brunogirin
When trying to run tox in parallel as explained on page 151, I got the following error: tox: error: argument -p/–parallel: expected one...
New
dtonhofer
@parrt In the context of Chapter 4.3, the grammar Java.g4, meant to parse Java 6 compilation units, no longer passes ANTLR (currently 4....
New
gorkaio
root_layout: {PentoWeb.LayoutView, :root}, This results in the following following error: no “root” html template defined for PentoWeb...
New

Other popular topics Top

siddhant3030
I’m thinking of buying a monitor that I can rotate to use as a vertical monitor? Also, I want to know if someone is using it for program...
New
dasdom
No chair. I have a standing desk. This post was split into a dedicated thread from our thread about chairs :slight_smile:
New
PragmaticBookshelf
Rust is an exciting new programming language combining the power of C with memory safety, fearless concurrency, and productivity boosters...
New
Exadra37
I am asking for any distro that only has the bare-bones to be able to get a shell in the server and then just install the packages as we ...
New
PragmaticBookshelf
Author Spotlight Rebecca Skinner @RebeccaSkinner Welcome to our latest author spotlight, where we sit down with Rebecca Skinner, auth...
New
New
husaindevelop
Inside our android webview app, we are trying to paste the copied content from another app eg (notes) using navigator.clipboard.readtext ...
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New
PragmaticBookshelf
Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic. Sam Ruby @rubys ...
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: