
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 thebigOf()
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 ofassertAll()
. It is cleaner to move the initialization ofFactorial
into 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());
}
}
Popular Pragmatic Bookshelf topics

Following the steps described in Chapter 6 of the book, I’m stuck with running the migration as described on page 84:
bundle exec sequel...
New

Title: Design and Build Great Web APIs - typo “https://company-atk.herokuapp.com/2258ie4t68jv” (page 19, third bullet in URL list)
Typo:...
New

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

I am working on the “Your Turn” for chapter one and building out the restart button talked about on page 27. It recommends looking into ...
New

I ran this command after installing the sample application:
$ cards add do something --owner Brian
And got a file not found error:
Fil...
New

I found an issue in Chapter 7 regarding android:backgroundTint vs app:backgroundTint.
How to replicate:
load chapter-7 from zipfile i...
New

Is the book’s epub format available to read on Google Play Books?
New

On page 78 the following code appears:
<%= link_to ‘Destroy’, product,
class: ‘hover:underline’,
method: :delete,
data: { confirm...
New

Hi all,
currently I wonder how the Tailwind colours work (or don’t work).
For example, in app/views/layouts/application.html.erb I have...
New

Getting an error when installing the dependencies at the start of this chapter:
could not compile dependency :exla, "mix compile" failed...
New
Other popular topics

Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New

If you are experiencing Rails console using 100% CPU on your dev machine, then updating your development and test gems might fix the issu...
New

Create efficient, elegant software tests in pytest, Python's most powerful testing framework.
Brian Okken @brianokken
Edited by Kat...
New

This is going to be a long an frequently posted thread.
While talking to a friend of mine who has taken data structure and algorithm cou...
New

Author Spotlight
Jamis Buck
@jamis
This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New

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

Programming Ruby is the most complete book on Ruby, covering both the language itself and the standard library as well as commonly used t...
New

I have always used antique keyboards like Cherry MX 1800 or Cherry MX 8100 and almost always have modified the switches in some way, like...
New

I’m able to do the “artistic” part of game-development; character designing/modeling, music, environment modeling, etc.
However, I don’t...
New

Node.js v22.14.0 has been released.
Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /ruby
- /wasm
- /erlang
- /phoenix
- /keyboards
- /rails
- /python
- /js
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /onivim
- /typescript
- /svelte
- /crystal
- /c-plus-plus
- /kotlin
- /tailwind
- /react
- /gleam
- /ocaml
- /flutter
- /elm
- /vscode
- /ash
- /opensuse
- /html
- /centos
- /php
- /deepseek
- /zig
- /scala
- /textmate
- /lisp
- /sublime-text
- /nixos
- /debian
- /react-native
- /agda
- /kubuntu
- /arch-linux
- /django
- /revery
- /ubuntu
- /manjaro
- /spring
- /nodejs
- /diversity
- /lua
- /deno
- /julia
- /slackware
- /c