1
\$\begingroup\$

I'm writing some unit tests for testing C# code but I'm using F# and Unquote for the first time for the unit tests and would like some input as to how I might make the tests more 'f-sharpier' to take advantage of and learn more about the functional approach in F#. Here's an example of one of my tests - please make recommendations:

[<Fact>]
let ``Two courses, one with one time and one with two times that all differ, returns two unique schedules with two entries each``() =
    // arrange
    let course1 = getCourse1()
    let course2 = getCourse2()
    let time1 = getTime1()
    let time2 = getTime2()
    let time3 = getTime3()
    time1 |> course1.AddTime
    time2 |> course2.AddTime
    time3 |> course2.AddTime

    let courses = List<Course>()
    [|course1; course2 |] |> courses.AddRange

    let scheduleEntry1 = ScheduleEntry(course1, time1)
    let scheduleEntry2 = ScheduleEntry(course2, time2)
    let scheduleEntry3 = ScheduleEntry(course2, time3)

    // act
    let schedules = courses |> ScheduleGenerator.Schedulize

    // assert
    test <@ schedules.Count() = 2 @>

    let allSchedulesHave2Entries = schedules.All(fun schedule -> schedule.Count() = 2)
    test <@ allSchedulesHave2Entries @>

    let hasSchedule entries = schedules.Any(fun schedule -> schedule.ToArray() = entries)
    test <@ hasSchedule [| scheduleEntry1; scheduleEntry2 |] @>
    test <@ hasSchedule [| scheduleEntry1; scheduleEntry3 |] @>

ScheduleGenerator.Schedulize returns an IEnumerable<IEnumerable<ScheduleEntry>> which is the type of schedules. So the type of schedule is just IEnumerable<ScheduleEntry>.

What ScheduleGenerator.Schedulize does is take a set of courses IEnumerable<Course>, where each course contains all available times for the course, and computes the Cartesian product for all the times across all the courses and then filters out any schedule which contains conflicting times.

\$\endgroup\$
6
  • \$\begingroup\$ why not just let courses = [|course1; course2 |] instead of let courses = List<Course>() [|course1; course2 |] |> courses.AddRange? \$\endgroup\$
    – user110704
    Aug 5 '16 at 17:31
  • \$\begingroup\$ And instead of schedules.All better schedules |> Seq.forall - more F#-style. \$\endgroup\$
    – user110704
    Aug 5 '16 at 17:35
  • \$\begingroup\$ It is really weird to me seeing <@ @> and the test function. This is type provider syntax right ? What is the advantage of simply using the Assert methods? \$\endgroup\$
    – asibahi
    Aug 5 '16 at 18:08
  • \$\begingroup\$ @asibahi, It`s Unquote \$\endgroup\$
    – user110704
    Aug 5 '16 at 18:38
  • \$\begingroup\$ @FoggyFinder I looked it up but if I understand correctly it doesn't change xUnit's behavior, right? It is only different from regular asserts when printing to FSI? \$\endgroup\$
    – asibahi
    Aug 5 '16 at 18:39
1
\$\begingroup\$

I guess I mostly needed to figure out how to replace LINQ with F# equivalents and then refactor a bit. Now I have this:

let ToArrays schedules = 
    schedules 
    |> Seq.map (fun schedule -> schedule |> Seq.toArray) 
    |> Seq.toArray

[<Fact>]
let ``Two courses, one with one time and one with two times that all differ, returns two unique schedules with two entries each``() =
    // arrange
    let course1 = getCourse1()
    let course2 = getCourse2()
    let time1 = getTime1()
    let time2 = getTime2()
    let time2a = getTime2a()
    time1 |> course1.AddTime
    time2 |> course2.AddTime
    time2a |> course2.AddTime

    let schedulesExpected =
        [| 
            [| ScheduleEntry(course1, time1); ScheduleEntry(course2, time2) |] 
            [| ScheduleEntry(course1, time1); ScheduleEntry(course2, time2a) |] 
        |]

    // act
    let schedulesActual = [| course1; course2 |] |> ScheduleGenerator.Schedulyze

    // assert
    test <@ schedulesActual |> ToArrays = schedulesExpected @>
\$\endgroup\$
2
  • \$\begingroup\$ instead of |> Seq.map (fun schedule -> schedule |> Seq.toArray) you can use just |> Seq.map (Seq.toArray) \$\endgroup\$
    – user110704
    Aug 6 '16 at 6:09
  • \$\begingroup\$ @FoggyFinder - it's IEnumerable<IEnumerable<ScheduleEntry>> so both the inner and outer need to be converted to arrays to get structural equality required in the test. And thanks for your earlier comments which got me pointed in the right path \$\endgroup\$ Aug 6 '16 at 17:31

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.