{"id":13546426,"url":"https://github.com/mausch/Fuchu","last_synced_at":"2025-04-02T18:30:42.540Z","repository":{"id":2162212,"uuid":"3108028","full_name":"mausch/Fuchu","owner":"mausch","description":"Functional test library for F# / C# / VB.NET","archived":false,"fork":false,"pushed_at":"2023-08-24T05:50:12.000Z","size":3031,"stargazers_count":120,"open_issues_count":18,"forks_count":22,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-05-06T09:35:32.861Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"dirkriehle/wahlzeit","license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mausch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2012-01-05T05:22:40.000Z","updated_at":"2024-03-27T15:15:41.000Z","dependencies_parsed_at":"2024-01-02T22:49:59.192Z","dependency_job_id":null,"html_url":"https://github.com/mausch/Fuchu","commit_stats":{"total_commits":331,"total_committers":7,"mean_commits":"47.285714285714285","dds":"0.12688821752265866","last_synced_commit":"8206851c5fa00a8462b7c0576ba059f00b6b3f75"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mausch%2FFuchu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mausch%2FFuchu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mausch%2FFuchu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mausch%2FFuchu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mausch","download_url":"https://codeload.github.com/mausch/Fuchu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246869647,"owners_count":20847168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T12:00:37.061Z","updated_at":"2025-04-02T18:30:42.004Z","avatar_url":"https://github.com/mausch.png","language":"F#","readme":"# Fuchu #\r\n\r\n**Fuchu** (pronounced \"foo choo\" with the accent on the last syllable) is a test library for .NET, supporting C# and VB.NET but with a special focus on F#.\r\nIt draws heavily from Haskell's [test-framework](http://batterseapower.github.com/test-framework/) and [HUnit](http://hunit.sourceforge.net/).\r\nYou can read about the rationale and underlying concepts in [this blog post](http://bugsquash.blogspot.com/2012/06/fuchu-functional-test-library-for-net.html),\r\nor TL;DR: tests should be first-class values so that you can move them around and execute\r\nthem in any context that you want. Also, if they are first-class values, then you can take\r\nextra care with what the test methods return, making integrations with external libraries\r\nmuch cheaper.\r\n\r\n## Binaries ##\r\n\r\nBinaries are available on [NuGet](http://nuget.org/packages?q=Fuchu).\r\n\r\n## Source ##\r\n\r\nAdd the following line to your paket.dependencies file\r\n\r\n    github mausch/Fuchu Fuchu/Fuchu.fs\r\n\r\n## Writing tests ##\r\n\r\nHere's the simplest test possible:\r\n\r\n```f#\r\nopen Fuchu\r\n\r\nlet simpleTest =\r\n    testCase \"A simple test\" \u003c| \r\n        fun _ -\u003e Assert.Equal(\"2+2\", 4, 2+2)\r\n```\r\n\r\nTests can be grouped (with arbitrary nesting):\r\n\r\n```f#\r\nlet tests = \r\n    testList \"A test group\" [\r\n        testCase \"one test\" \u003c|\r\n            fun _ -\u003e Assert.Equal(\"2+2\", 4, 2+2)\r\n        testCase \"another test\" \u003c|\r\n            fun _ -\u003e Assert.Equal(\"3+3\", 3, 3+3)\r\n    ]\r\n```\r\n\r\nIn C#:\r\n\r\n```c#\r\nstatic Test ATest {\r\n    get {\r\n        return Test.List(\"A test group\", new[] {\r\n            Test.Case(\"one test\", () =\u003e Assert.Equal(\"2+2\", 4, 2+2)),\r\n            Test.Case(\"another test\", () =\u003e Assert.Equal(\"3+3\", 3, 3+3)),\r\n        });\r\n    }\r\n}\r\n```\r\n    \r\nThe first parameter in the assertions describes the assertion. This is usually an optional parameter in most test frameworks; in Fuchu it's required to foster descriptive failures, so you'll get a failure like \"3+3 Expected value 3, actual 6\" instead of just \"Expected value 3, actual 6\".\r\n\r\nFor more examples, including a few ways to do common things in other test frameworks like setup/teardown and parameterized tests, see the [F# tests](https://github.com/mausch/Fuchu/blob/master/Fuchu.Tests/Tests.fs) and the [C# tests](https://github.com/mausch/Fuchu/blob/master/Fuchu.CSharpTests/Program.cs)\r\n\r\n## Assertions ##\r\n\r\nFuchu is mainly oriented to test organization. Although it does have a few basic assertions, you're encouraged to write your own specialized assertions for each project (they're only a couple of lines in F#), or use some other library for assertions, like [Unquote](http://code.google.com/p/unquote/), [FsUnit](https://github.com/dmohl/FsUnit), or even MbUnit or NUnit.\r\n\r\n## Running tests ##\r\n\r\nThe test runner is the test assembly itself. It's recommended to compile your test assembly as a console application. You can run a test directly like this:\r\n\r\n```f#\r\nrun simpleTest // or runParallel\r\n```\r\n\r\nwhich returns 1 if any tests failed, otherwise 0. Useful for returning to the operating system as error code. Or you can mark the top-level test in each test file with the `[\u003cTests\u003e]` attribute, then define your main like this:\r\n\r\n```f#\r\nopen Fuchu\r\n\r\n[\u003cEntryPoint\u003e]\r\nlet main args = defaultMainThisAssembly args\r\n```\r\n    \r\nThis `defaultMainThisAssembly` function admits a \"/m\" parameter passed through the command-line to run tests in parallel. In order to get diagnostic messages you pass in a \"/d\".\r\n    \r\nYou can single out tests by filtering them by name. For example:\r\n\r\n```f#\r\ntests\r\n|\u003e Test.filter (fun s -\u003e s.EndsWith \"another test\")\r\n|\u003e run\r\n```\r\n\r\nYou can use the F# REPL to run tests this way.\r\n\r\n### F\\# Script ###\r\n\r\nIn a F# script you can use that F# is able to load NuGet assemblies directly.\r\n\r\n```f#\r\n#r \"nuget: Fuchu\"\r\nopen Fuchu\r\nlet simpleTest = \r\n    testCase \"A simple test\" \u003c| \r\n        fun _ -\u003e Assert.Equal(\"2+2\", 4, 2+2)\r\nrun simpleTest\r\n```\r\n\r\n### Using Fuchu with C\\# ###\r\n\r\nIn C#:\r\n\r\n```c#\r\nstatic int Main(string[] args) {\r\n    return ATest.Run(); // or RunParallel()\r\n}\r\n```\r\n\r\nOr scanning for tests marked with the [Tests] attribute:\r\n\r\n```c#\r\nstatic int Main(string[] args) {\r\n    return Tests.DefaultMainThisAssembly(args);\r\n}\r\n```\r\n\r\n### Using Fuchu with Fable ###\r\n\r\nIn order to be able to test your code both with .net and Fable you can adjust your main:\r\n\r\n```f#\r\nopen Fuchu\r\n#if FABLE_COMPILER\r\nlet exitIfNonZero v =\r\n    if v \u003c\u003e 0 then\r\n        failwithf \"expected a nonzero exitcode, but got %i\" v\r\n    v\r\n#endif\r\n\r\n[\u003cEntryPoint\u003e]\r\nlet main args =\r\n    defaultMain Tests.tests args\r\n    #if FABLE_COMPILER\r\n    |\u003e exitIfNonZero\r\n    #endif\r\n```\r\n\r\nNote that we don't use assembly scanning with Fable.\r\n\r\nYou will need to have [esm](https://www.npmjs.com/package/esm) installed, leaving you with the following package.json:\r\n\r\n    {\r\n        \"private\": true,\r\n        \"dependencies\": {\r\n            \"esm\": \"^3.2.25\"\r\n        },\r\n        \"name\": \"tests\"\r\n    }\r\n\r\nIn order to run the tests with Fable you then use `dotnet fable` to run your test project:\r\n\r\n    dotnet fable YourTestProject --outDir bin --runScript\r\n\r\n## FsCheck integration ##\r\n\r\nReference [FsCheck](http://fscheck.codeplex.com/) and Fuchu.FsCheck to test properties:\r\n\r\n```f#\r\nlet config = { FsCheck.Config.Default with MaxTest = 10000 }\r\n\r\nlet properties = \r\n    testList \"FsCheck\" [\r\n        testProperty \"Addition is commutative\" \u003c|\r\n            fun a b -\u003e \r\n                a + b = b + a\r\n        \r\n        // you can also override the FsCheck config\r\n        testPropertyWithConfig config \"Product is distributive over addition\" \u003c|\r\n            fun a b c -\u003e \r\n                a * (b + c) = a * b + a * c\r\n    ]\r\n\r\nrun properties\r\n```\r\n    \r\nIn C# (can't override FsCheck config at the moment):\r\n\r\n```c#\r\nstatic Test Properties =\r\n    Test.List(\"FsCheck\", new[] {\r\n        FsCheck.Property(\"Addition is commutative\",\r\n                            (int a, int b) =\u003e a + b == b + a),\r\n        FsCheck.Property(\"Product is distributive over addition\",\r\n                            (int a, int b, int c) =\u003e a * (b + c) == a * b + a * c),\r\n    });\r\n```\r\n\r\nYou can freely mix FsCheck properties with regular test cases and test lists.\r\n\r\n## PerfUtil integration ##\r\n\r\nThe integration with Eirik's PerfUtil project.\r\n\r\n```f#\r\nopen global.PerfUtil\r\n\r\nmodule Types =\r\n    type Y = { a : string; b : int }\r\n\r\ntype Serialiser =\r\n    inherit ITestable\r\n    abstract member Serialise\u003c'a\u003e : 'a -\u003e unit\r\n\r\ntype MySlowSerialiser() =\r\n    interface ITestable with\r\n        member x.Name = \"Slow Serialiser\"\r\n    interface Serialiser with\r\n        member x.Serialise _ =\r\n            System.Threading.Thread.Sleep(30)\r\n\r\ntype FastSerialiser() =\r\n    interface ITestable with\r\n        member x.Name = \"Fast Serialiser\"\r\n    interface Serialiser with\r\n        member x.Serialise _ =\r\n            System.Threading.Thread.Sleep(10)\r\n\r\ntype FastSerialiserAlt() =\r\n    interface ITestable with\r\n        member x.Name = \"Fast Serialiser Alt\"\r\n    interface Serialiser with\r\n        member x.Serialise _ =\r\n            System.Threading.Thread.Sleep(20)\r\n\r\nlet alts : Serialiser list = [ FastSerialiser(); FastSerialiserAlt() ]\r\nlet subj = MySlowSerialiser() :\u003e Serialiser\r\n\r\nopen Types\r\n\r\nlet normal_serlialisation : PerfTest\u003cSerialiser\u003e list = [\r\n    perfTest \"serialising string\" \u003c| fun s -\u003e\r\n        s.Serialise(\"wowowow\")\r\n    perfTest \"serialising record\" \u003c| fun s -\u003e\r\n        s.Serialise { a = \"hello world\"; b = 42 }\r\n    ]\r\n\r\n[\u003cTests\u003e]\r\nlet tests =\r\n    testList \"performance comparison tests\" [\r\n        testPerfImpls \"implementations of Serialiser\" subj alts normal_serlialisation\r\n        testPerfHistory \"historical MySlowSerialiser\" subj \"v1.2.3\" normal_serlialisation\r\n    ]\r\n```\r\n\r\nThis example shows both a comparison performance test between MySlowSerialiser, FastSerialiser and\r\nFastSerialiserAlt: `testPerfImpls` and a historical comparison of MySlowSerialiser alone\r\nwhich saves an xml file next to the dll on every run.\r\n\r\nYou can find detailed docs in the source code of PerfUtil.fs on all parameters and data\r\nstructures. All things that can be configured with PerfUtil can be configured with the\r\n`conf` parameter to `testPerfImplsWithConfig` and `testPerfHistoryWithConfig`.\r\n\r\nThe functions are discoverable by starting with `testPerf*`.\r\n\r\nHandle the results explicitly by giving a config with a value of `handleResults`. Use\r\nthat if you want to export the data to e.g. CSV or TSV.\r\n\r\n## More examples ##\r\n\r\nSome projects using Fuchu:\r\n\r\n* [FsSql](https://github.com/mausch/FsSql/tree/master/FsSql.Tests)\r\n* [FsFormlets](https://github.com/mausch/FsFormlets/tree/master/Formlets.Tests)\r\n* UrchiNet ([C#](https://github.com/mausch/UrchiNet/blob/master/UrchiNet.CSharpTests/Tests.cs) and [F#](https://github.com/mausch/UrchiNet/blob/master/UrchiNet.Tests/Tests.fs))\r\n* [Figment](https://github.com/mausch/Figment/tree/master/Figment.Tests)\r\n* [NHWebConsole](https://github.com/mausch/NHWebConsole/tree/master/NHWebConsole.Tests)\r\n* [Fleece](https://github.com/mausch/Fleece/blob/master/Tests/Tests.fs)\r\n* [EdmundsNet](https://github.com/mausch/EdmundsNet/blob/master/Tests/Tests.fs)\r\n* [Suave](https://github.com/SuaveIO/suave/tree/master/src/Suave.Tests)\r\n","funding_links":[],"categories":["F# #","Testing","测试"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmausch%2FFuchu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmausch%2FFuchu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmausch%2FFuchu/lists"}