We are trying to mock type/class with static method , but unable to do it in fSharp, Is there any way to mock it? we are getting "* Type to mock ( TestRepository) must be an interface, a delegate, or a non-sealed, non-static class " error.
Sample Class :
type TestRepository<'V when 'V :> Iview> =
{ executeQuery: IQueryable<'T> ->Task<Result<seq<'T>, exn>> }
static member Create<'V when 'V :> Iview> state : TestRepository<'V> =
{
executeQuery = executeQuery<'V> typeof<'V>.FullName state
}
Welcome Aman!
How exactly are you trying to mock it? It sounds like you’re using some mocking library? I doubt that a mocking library is going to be able to mock a static member on a class. For that matter, it’s probably not going to be able to mock an F# record at all whether there is a static member or not because I believe F# records will be sealed, and the message says it only works for non-sealed classes. You could build a non-sealed class without using a record:
type TestRepository<'V when 'V :> Iview> (executeQuery : IQueryable<'T> -> Task<Result<seq<'T>, exn>>) =
member this.ExecuteQuery src = executeQuery src
static member Create<'V when 'V :> Iview> state = TestRepository (executeQuery<'V> typeof<'V>.FullName state)
though you still probably can’t mock the static member with your mocking library.
That said, if in your consumer you use the F# 7 SRTP syntax to refer to the static method:
let inline consumer<'a when 'a :> TestRepository<_> and 'a : (static member Create : State -> 'a) > =
let repo = 'a.Create state
...
then you should be able to use any type that inherits from TestRepository and defines a static member Create, so you could probably roll your own mock rather than use a library.
SRTP is considered pretty advanced though, and I haven’t tested the code I wrote so YMMV. You might want to consider just simplifying the process by ditching mocks and using regular function passing and partial application:
let consumer (queryFactory : State -> (IQueryable<'T> -> Task<Result<seq<'T, exn>>)) = task {
let execQuery = queryFactory state
let! results = execQuery ...
}
...
// from prod - partially apply the real `executeQuery` as the factory function, just like your code sample
consumer (executeQuery<'V> typeof<'V>.FullName)
...
// from tests, "mock" a Repository, but without a mocking library
let mockQuery (_:IQueryable<'T>) = task {
printfn "Here I mock running a query"
return Error (exn ("test failure"))
}
consumer (fun _ -> mockQuery)