 
  		        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 Factorialclass has been given a constructor printing something when it is called (just for fun)
- Creating BigIntegerinstances 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 @BeforeEachmethod as shown in the book, as that method is only called once even in the presence ofassertAll(). It is cleaner to move the initialization ofFactorialinto the individual@Testmethods 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
                         
                      
                       
          
                page 20: … protoc command… 
I had to additionally run the following go get commands in order to be able to compile protobuf code using go...
              
            
            
          
              New
 
          
                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
 
          
                In case this helps anyone, I’ve had issues setting up the rails source code. Here were the solutions: 
In Gemfile, change 
gem 'rails'
t...
              
            
            
          
              New
 
          
                Is the book’s epub format available to read on Google Play Books?
              
            
            
          
              New
 
          
                Is there any place where we can discuss the solutions to some of the exercises? I can figure most of them out, but am having trouble with...
              
            
            
          
              New
 
          
                On page 78 the following code appears: 
<%= link_to ‘Destroy’, product, 
class: ‘hover:underline’, 
method: :delete, 
data: { confirm...
              
            
            
          
              New
 
          
                It seems the second code snippet is missing the code to set the current_user: 
current_user: Accounts.get_user_by_session_token(session["...
              
            
            
          
              New
 
          
                Hi, I’ve got a question about the implementation of PubSub when using a Phoenix.Socket.Transport behaviour rather than channels. 
Before ...
              
            
            
          
              New
 
          
                Book: Programming Phoenix LiveView, page 142 (157/378), file lib/pento_web/live/product_live/form_component.ex, in the function below: 
d...
              
            
            
          
              New
 
          
                I’ve got to the end of Ch. 11, and the app runs, with all tabs displaying what they should – at first.  After switching around between St...
              
            
            
          
              New
Other popular topics
                         
                      
                       
          
                Which, if any, games do you play? On what platform? 
I just bought (and completed) Minecraft Dungeons for my Nintendo Switch. Other than ...
              
            
            
          
              New
 
          
                I am thinking in building or buy a desktop computer for programing, both professionally and on my free time, and my choice of OS is Linux...
              
            
            
          
              New
 
          
                There’s a whole world of custom keycaps out there that I didn’t know existed! 
Check out all of our Keycaps threads here: 
https://forum....
              
            
            
          
              New
 
          
                Do the test and post your score :nerd_face: 
:keyboard: 
If possible, please add info such as the keyboard you’re using, the layout (Qw...
              
            
            
              
          
              New
 
          
                Biggest jackpot ever apparently! :upside_down_face: 
I don’t (usually) gamble/play the lottery, but working on a program to predict the...
              
            
            
          
              New
 
          
                Author Spotlight 
Erin Dees 
@undees 
Welcome to our new author spotlight! We had the pleasure of chatting with Erin Dees, co-author of ...
              
            
            
          
              New
 
          
                There appears to have been an update that has changed the terminology for what has previously been known as the Taskbar Overflow - this h...
              
            
            
          
              New
 
          
                Will Swifties’ war on AI fakes spark a deepfake porn reckoning? 
              
            
            
              
          
              New
 
          
                If you’re getting errors like this: 
psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
              
            
            
          
              New
 
          
                Fight complexity and reclaim the original spirit of agility by learning to simplify how you develop software. The result: a more humane a...
              
            
            
              
          
              New
Categories:
Sub Categories:
Popular Portals
- /elixir
- /rust
- /ruby
- /wasm
- /erlang
- /phoenix
- /keyboards
- /python
- /rails
- /js
- /security
- /go
- /swift
- /vim
- /clojure
- /emacs
- /haskell
- /java
- /svelte
- /onivim
- /typescript
- /kotlin
- /c-plus-plus
- /crystal
- /tailwind
- /react
- /gleam
- /ocaml
- /elm
- /flutter
- /vscode
- /ash
- /html
- /opensuse
- /centos
- /php
- /zig
- /deepseek
- /scala
- /lisp
- /textmate
- /sublime-text
- /react-native
- /nixos
- /debian
- /agda
- /kubuntu
- /arch-linux
- /django
- /revery
- /deno
- /ubuntu
- /spring
- /manjaro
- /nodejs
- /diversity
- /lua
- /julia
- /slackware
- /c
 
    





