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

jeffmcompsci
Title: Design and Build Great Web APIs - typo “https://company-atk.herokuapp.com/2258ie4t68jv” (page 19, third bullet in URL list) Typo:...
New
jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
yulkin
your book suggests to use Image.toByteData() to convert image to bytes, however I get the following error: "the getter ‘toByteData’ isn’t...
New
Alexandr
Hi everyone! There is an error on the page 71 in the book “Programming machine learning from coding to depp learning” P. Perrotta. You c...
New
patoncrispy
I’m new to Rust and am using this book to learn more as well as to feed my interest in game dev. I’ve just finished the flappy dragon exa...
New
curtosis
Running mix deps.get in the sensor_hub directory fails with the following error: ** (Mix) No SSH public keys found in ~/.ssh. An ssh aut...
New
Charles
In general, the book isn’t yet updated for Phoenix version 1.6. On page 18 of the book, the authors indicate that an auto generated of ro...
New
brunogirin
When installing Cards as an editable package, I get the following error: ERROR: File “setup.py” not found. Directory cannot be installe...
New
AufHe
I’m a newbie to Rails 7 and have hit an issue with the bin/Dev script mentioned on pages 112-113. Iteration A1 - Seeing the list of prod...
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

PragmaticBookshelf
Stop developing web apps with yesterday’s tools. Today, developers are increasingly adopting Clojure as a web-development platform. See f...
New
AstonJ
Curious to know which languages and frameworks you’re all thinking about learning next :upside_down_face: Perhaps if there’s enough peop...
New
New
PragmaticBookshelf
Build highly interactive applications without ever leaving Elixir, the way the experts do. Let LiveView take care of performance, scalabi...
New
Help
I am trying to crate a game for the Nintendo switch, I wanted to use Java as I am comfortable with that programming language. Can you use...
New
PragmaticBookshelf
Author Spotlight: VM Brasseur @vmbrasseur We have a treat for you today! We turn the spotlight onto Open Source as we sit down with V...
New
PragmaticBookshelf
Author Spotlight: Peter Ullrich @PJUllrich Data is at the core of every business, but it is useless if nobody can access and analyze ...
New
NewsBot
Node.js v22.14.0 has been released. Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
New
PragmaticBookshelf
Fight complexity and reclaim the original spirit of agility by learning to simplify how you develop software. The result: a more humane a...
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: