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.
1 Answer 1
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 @>
-
\$\begingroup\$ instead of
|> Seq.map (fun schedule -> schedule |> Seq.toArray)
you can use just|> Seq.map (Seq.toArray)
\$\endgroup\$user110704– user1107042016年08月06日 06:09:03 +00:00Commented 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\$Coding Dude– Coding Dude2016年08月06日 17:31:18 +00:00Commented Aug 6, 2016 at 17:31
let courses = [|course1; course2 |]
instead oflet courses = List<Course>() [|course1; course2 |] |> courses.AddRange
? \$\endgroup\$schedules.All
betterschedules |> Seq.forall
- more F#-style. \$\endgroup\$<@ @>
and thetest
function. This is type provider syntax right ? What is the advantage of simply using theAssert
methods? \$\endgroup\$