2
\$\begingroup\$

I would like to ask 2 questions about the modularization of an F# file. The code is just a working example of prime factorization, but that's not the main topic. I have a main file (PrimeFactors.fs), a different file for its mocked version (PrimeFactorsMock.fs), and a test file (PrimeFactorsTests.fs):

PrimeFactors.fs

namespace PrimeFactors

module PrimeFactors = 

    type IPrimeChecker =
        abstract member IsPrime : int64 -> int64 -> bool        

    type PrimeFactors() = 
        interface IPrimeChecker with
            member this.IsPrime number i =
                number % i = 0L

        member this.CheckPrimes number i acc =
            match i with
                | _ when i > (number |> float |> sqrt |> int64)   -> number::acc
                | _ when (this :> IPrimeChecker).IsPrime number i -> this.CheckPrimes (number / i) i (i::acc)
                | _                                               -> this.CheckPrimes number (i + 1L) acc

        member this.Of number =
            if number = 1L then
                [||]
            else
                this.CheckPrimes number 2L [] |> List.toArray

PrimeFactorsMock.fs

namespace PrimeFactors
open PrimeFactors

module PrimeFactorsMock =
    type PrimeFactorsMock() =
        inherit PrimeFactors() 

        let mutable stepCount = 0L

        interface IPrimeChecker with
          member this.IsPrime number i =
            stepCount <- stepCount + 1L
            number % i = 0L

        member this.StepCount number =
            stepCount <- 0L
            this.Of number |> ignore
            stepCount

PrimeFactorsTests.fs

namespace PrimeFactors

open PrimeFactors
open NUnit.Framework
open FsUnit
open PrimeFactorsMock

[<TestFixture>]
module PrimeFactorTests =

    [<TestCase(1L, [||])>]
    [<TestCase(2L, [|2L|])>]
    [<TestCase(3L, [|3L|])>]
    [<TestCase(4L, [|2L; 2L|])>]
    [<TestCase(6L, [|3L; 2L|])>]
    [<TestCase(8L, [|2L; 2L; 2L|])>]
    [<TestCase(16L, [|2L; 2L; 2L; 2L|])>]
    [<TestCase(773L, [|773L|])>]
    [<TestCase(8L, [|2L; 2L; 2L|])>]
    let prime_factors_of_number number expect =
        PrimeFactors().Of number |> should equal expect

    [<TestCase(1L, 0L)>]
    [<TestCase(4L, 1L)>]
    [<TestCase(773L, 26L)>]
    let step_count_of_number number stepCount =
        PrimeFactorsMock().StepCount number |> should equal stepCount

What I like in that solution it's mock version is separated rightly from the initial class. So I only have to redefine IPrimeChecker.IsPrime, not the this.CheckPrimes, and possible all the inner functions. So I made IsPrime, and only IsPrime, virtual. It's a poor man's mocking.

My question is about mocking with object expression if that could be achieved without creating the PrimeFactorsMock.fs, and less coding. If we redefine the whole PrimeFactorsMock in the test file, it doesn't count (at least make it smaller). The goal is to make the IsPrime function interchangeable in the test file without much hassle.

The other question is I would like to use active patterns for IsPrime. So I can use pattern matching with (|Prime|NonPrime|) in the this.CheckPrimes part. Restriction is that have to be same as interchangeable as the already implemented virtual IsPrime.

\$\endgroup\$
1
\$\begingroup\$

The first thing I notice is the somewhat misleading method name IsPrime. I would call it IsFactor, because it only checks if i is a factor of number - not if it is a prime factor.


Secondly I think it is a problem that PrimeFactorsMock.IsPrime has its own implementation of number % i = 0L because you then don't evaluate the base class implementation which could be invalid.

A solution to that problem could be as shown below. Be aware that I have dropped the IPrimeChecker, because it is unnecessary.

module PrimeFactors = 

    type PrimeFactors() = 

        // I've renamed IsPrime to IsFactor because it is only checking if i is a factor of number not if it is a prime factor
        // You have to tuple the arguments to make it possible to be called from a derived class by base.IsFactor
        abstract member IsFactor: uint64 * uint64 -> bool
        default this.IsFactor (number, i) = number % i = 0UL

        member this.CheckPrimes number i acc =
            match i with
                | _ when i > (number |> float |> sqrt |> uint64)   -> number::acc
                | _ when this.IsFactor (number, i) -> this.CheckPrimes (number / i) i (i::acc)
                | _  -> this.CheckPrimes number (i + 1UL) acc

        member this.Of number =
            if number = 1UL then
                [||]
            else
                this.CheckPrimes number 2UL [] |> List.toArray




module PrimeFactorsMock =
    open PrimeFactors

    type PrimeFactorsMock() =
        inherit PrimeFactors() 

        let mutable stepCount = 0L

        override this.IsFactor (number, i) = 
            stepCount <- stepCount + 1L
            base.IsFactor (number, i) // Her the base class implementation is called

        member this.StepCount number =
            stepCount <- 0L
            this.Of number |> ignore
            stepCount

When it comes to Object Expressions as a mock for testing, I haven't found a valid approach in this case, because you can't extend an OE beyond the type you "derive" from. For instance the below straight forward solution is not an option:

let mock = { 
    new PrimeFactors.PrimeFactors()
    with 
        member this.IsFactor (number, i) =
            stepCount <- stepCount + 1L
            base.IsFactor (number, i)

    // This is not allowed
    let mutable stepCount = 0L
    member this.StepCount number =
        stepCount <- 0L
        this.Of number |> ignore
        stepCount

}

According to Active Patterns for Prime|NoPrime (or is it Factor?) I would use a union type instead defined as follows:

type FactorType =
    | Factors of uint64 * uint64
    | NonFactor

- used in a way like this:

let getFactorType a b = 
            match a % b with
            | r when r = 0UL -> Factors(b, a / b)
            | _ -> NonFactor

- and matched like this:

match getFactorType num i with
| Factors(a, b) -> getPrimes b a (a::acc)
| NonFactor -> getPrimes num (i + 1UL) acc

An entire solution that uses a discriminated union type for factor/nonfactor and minimize the Mock derive could be as follows - not claiming it to be best practice or anything like that.

module PF = 

    // Instead of an active pattern, I use this discriminated union type
    type FactorType =
        | Factors of uint64 * uint64
        | NonFactor

    // Function prototype for functions testing if a number is a factor of another
    // I've changed the domain type from int64 to uint64 
    type FactorChecker = uint64 * uint64 -> FactorType

    type PrimeFactors() = 

        // This function is made static because it has nothing to do with the class itself
        // and because I want to reuse it in the derived Mock class (se below)
        // I renamed it to getFactorType from IsPrime, 
        // because IsPrime is somewhat misleading 
        // as it only checks if b is a factor of a not if it is a prime factor.
        static member getFactorType (a, b) = 
            match a % b with
            | r when r = 0UL -> Factors(b, a / b)
            | _ -> NonFactor

        // This could be static as well but here I made it a member. 
        // It would be nice to declare it protected, but that's not an option in F#
        // In order to let the client provide the function to check for factors, the last argument is a function of type FactorChecker
        member this.getFactors number (factorChecker: FactorChecker) = 
            if number < 2UL then
                []
            else
                // The stop condition is the (uint64 sqrt) of n
                let max n = n |> float |> sqrt |> uint64

                let rec getPrimes num i acc =                    
                    match i with
                    | _ when i > max num -> num::acc
                    | _ ->
                        match factorChecker (num, i) with
                        | Factors(a, b) -> getPrimes b a (a::acc)
                        | NonFactor -> getPrimes num (i + 1UL) acc

                getPrimes number 2UL []

        member this.Of (number: uint64) : uint64 list = this.getFactors number PrimeFactors.getFactorType

module PFMocks = 
    open PF

    // This is a simplified version of PrimeFactorsMock without the IsPrime override
    type PrimeFactorsMock() =
        inherit PrimeFactors() 

        member this.StepCount number =
            let mutable stepCount = 0L
            let facChecker (a, b) = 
                stepCount <- stepCount + 1L
                PrimeFactors.getFactorType (a, b)
            this.getFactors number facChecker |> ignore
            stepCount
\$\endgroup\$
  • 1
    \$\begingroup\$ Nice and thorough. I have almost made getFactorType static member (|DivisibleBy|_|) (a, b) =, but it doesn't let active pattern to be member. So PFMock can't see the default implementation. So I like the descriminated union better. \$\endgroup\$ – ntohl Mar 12 '18 at 10:57
  • \$\begingroup\$ Made a Kata about that: vimeo.com/263115590 \$\endgroup\$ – ntohl Apr 4 '18 at 8:38

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.