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.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 5, 2016 at 16:21
\$\endgroup\$
6
  • \$\begingroup\$ why not just let courses = [|course1; course2 |] instead of let courses = List<Course>() [|course1; course2 |] |> courses.AddRange? \$\endgroup\$ Commented Aug 5, 2016 at 17:31
  • \$\begingroup\$ And instead of schedules.All better schedules |> Seq.forall - more F#-style. \$\endgroup\$ Commented Aug 5, 2016 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\$ Commented Aug 5, 2016 at 18:08
  • \$\begingroup\$ @asibahi, It`s Unquote \$\endgroup\$ Commented Aug 5, 2016 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\$ Commented Aug 5, 2016 at 18:39

1 Answer 1

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 @>
answered Aug 6, 2016 at 3:27
\$\endgroup\$
2
  • \$\begingroup\$ instead of |> Seq.map (fun schedule -> schedule |> Seq.toArray) you can use just |> Seq.map (Seq.toArray) \$\endgroup\$ Commented Aug 6, 2016 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\$ Commented Aug 6, 2016 at 17:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.