Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test F# option types with xUnit

Tags:

f#

xunit.net

I want to unit test this bit of code using xUnit in F#. How do I handle the options?

From Scott Wlaschin's book: Domain Modeling Made Functional

type UnitQuantity = private UnitQuantity of int
// ^ private constructor

// define a module with the same name as the type
module UnitQuantity =
    /// Define a "smart constructor" for UnitQuantity
    /// int -> Result<UnitQuantity,string>
    let create qty =
        if qty < 1 then
            // failure
            Error "UnitQuantity can not be negative"
        else if qty > 1000 then
            // failure
            Error "UnitQuantity can not be more than 1000"
        else
            // success -- construct the return value
            Ok (UnitQuantity qty)

Test:

let ``Check UnitQuantity.create is one`` () =

    // ARRANGE
    let expected = 1

    // ACT
    //let unitQtyResult = UnitQuantity.create 1
    match UnitQuantity.create 1 with
    | Error msg -> 0
        //printfn "Failure, Message is %s" msg
    | Ok x -> 0
       // let innerValue = UnitQuantity.value actual

    // ASSERT
    //Assert.Equal(expected,actual)

I know the ACT is all wrong, that is where I am hung up. I do not understand F# options nor xUnit.net nor unit testing enough yet to Assert on the actual value from the function.

like image 576
netazoid Avatar asked Aug 14 '19 08:08

netazoid


People also ask

What is an F test in Excel?

F-Test in Excel. F-test in excel is a test which is used to decide if two populations having normal distribution have similar variances or the standard deviation. This is an essential part of the Analysis of Variance (ANOVA).

How do you interpret the ratio in an F test?

For an overall F-test, the ratio contains the variance accounted for by your model in the numerator and the variance accounted for by a model with no predictors in the denominator. If the ratio is significantly greater than one, you know that the numerator is significantly greater than the denominator.

How do you find the F value in statistics?

F value is a value on the F distribution. Various statistical tests generate an F value. The value can be used to determine whether the test is statistically significant. In order to compare two variances, one has to calculate the ratio of the two variances, which is as under: F Value = Larger Sample Variance / Smaller Sample Variance = σ12 / σ22.

What is an F-test formula?

(Step by Step) | Examples F-test formula is used in order to perform the statistical test that helps the person conducting the test in finding that whether the two population sets that are having the normal distribution of the data points of them have the same standard deviation or not. F-Test is any test that uses F-distribution.


2 Answers

I'd probably compare the result directly rather than pattern matching. However, you can't create an Ok result for Result<UnitQuantity, string> because of the private constructor.

You can use the built-in Result.map to map the Ok value of a result. Using UnitQuantity.value you can map from Result<UnitQuantity, string> to Result<int, string>. So this should work:

let expected = Ok 1

let actual = UnitQuantity.create 1 |> Result.map UnitQuantity.value

Assert.Equal(expected, actual)
like image 177
Charles Mager Avatar answered Sep 18 '22 01:09

Charles Mager


A general rule of thumb with unit tests is that the Act section should be a single statement.

Everything that we want to check about the result is some form of assertion

So we want to assert whether the result is either an Ok<UnitQuantity> or an Error<string>.

This is where pattern matching allows us to test this very succintly

let ``Check UnitQuantity.create is one`` () =
    // ARRANGE
    let qty = 1 // The quantity we supply is one
    let expected = qty // We expect to get that value back

    // ACT
    let actual = UnitQuantity.create qty

    // ASSERT

    // Check if we have an Ok or an Error
    match actual with
      | Ok unitQuantity ->
        // If Ok, check the value is what we expect
        let innerValue = UnitQuantity.value unitQuantity
        Assert.Equal(innerValue, expected)

      // If Error raise an AssertException to fail the test
      | Error errorMessage ->
        let error = sprintf "Expected Ok, was Error(%s)." errorMessage
        Assert.True(false, error) // Force an assertion failure with our error message

Note the UnitQuantity.value method, it' a simple unwrap function you can add to the end of the UnitQuantity module that will give you back the int value so you can easily compare it

let value (UnitQuantity e) = e

If you wanted to test an option type, it would be very similar, using a match statement like so

match actual with
  | Some value ->
    // Do your assertions here
    ()
  | None ->
    // Do your assertions here
    ()
like image 24
Simon Reynolds Avatar answered Sep 18 '22 01:09

Simon Reynolds