Unit testing an analyzer
To help analyzer authors testing their analyzers, there's a dedicated testing package. It contains easy to use utility functions to create a context for the analyzer and assertion helpers.
FSharp.Analyzers.SDK.Testing.mkOptionsFromProject creates the FSharpProjectOptions for the given framework (e.g. net7.0) and the given list of packages to reference.
FSharp.Analyzers.SDK.Testing.getContext then takes the FSharpProjectOptions and the source code to test and creates a CliContext you can pass along to your analyzer function.
The module FSharp.Analyzers.SDK.Testing.Assert offers various functions to help with assertion statements from your favorite unit testing framework.
For a complete example of an unit testing project, take a look at OptionAnalyzer.Test in the samples folder of the SDK repository.
open FSharp.Compiler.CodeAnalysis
open FSharp.Analyzers.SDK.Testing
open OptionAnalyzer
open NUnit.Framework
let mutable projectOptions: FSharpProjectOptions = FSharpProjectOptions.zero
[<SetUp>]
let Setup () =
task {
let! opts =
mkOptionsFromProject
"net7.0"
[
// The SDK uses this in a "dotnet add package x --version y" command
// to generate the needed FSharpProjectOptions
{
Name = "Newtonsoft.Json"
Version = "13.0.3"
}
]
projectOptions <- opts
}
[<Test>]
let ``warnings are emitted`` () =
async {
let source =
"""
module M
let notUsed() =
let option : Option<int> = None
option.Value
"""
let ctx = getContext projectOptions source
let! msgs = optionValueAnalyzer ctx
Assert.IsNotEmpty msgs
Assert.IsTrue(Assert.messageContains "Option.Value" msgs[0])
}
namespace FSharp
--------------------
namespace Microsoft.FSharp
type SetUpAttribute = inherit NUnitAttribute new: unit -> unit
--------------------
SetUpAttribute() : SetUpAttribute
<summary>Creates a classlib project in a temporary folder to gather the needed FSharpProjectOptions.</summary>
<param name="framework">The target framework for the tested code to use. E.g. net6.0, net7.0</param>
<param name="additionalPkgs">A list of additional packages that should be referenced. The tested code can use these.</param>
<returns>FSharpProjectOptions</returns>
type TestAttribute = inherit NUnitAttribute interface ISimpleTestBuilder interface IApplyToTest interface IImplyFixture new: unit -> unit member ApplyToTest: test: Test -> unit member BuildFrom: method: IMethodInfo * suite: Test -> TestMethod member Author: string member Description: string member ExpectedResult: obj ...
--------------------
TestAttribute() : TestAttribute
<summary>Creates CliContext for a given source and options.</summary>
<param name="opts">The project options to use.</param>
<param name="source">The file to analyze.</param>
<returns>CliContext</returns>
Assert.IsNotEmpty(aString: string) : unit
Assert.IsNotEmpty(collection: System.Collections.IEnumerable, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsNotEmpty(aString: string, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsTrue(condition: System.Nullable<bool>) : unit
Assert.IsTrue(condition: bool, message: string, [<System.ParamArray>] args: obj array) : unit
Assert.IsTrue(condition: System.Nullable<bool>, message: string, [<System.ParamArray>] args: obj array) : unit
FSharp.Analyzers.SDK