diff --git a/404.html b/404.html index dcb267ce0d..7b98b00170 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ Page Not Found | TUnit - + diff --git a/assets/js/5bed7376.1106c1a5.js b/assets/js/5bed7376.1106c1a5.js new file mode 100644 index 0000000000..eb0acf6e2d --- /dev/null +++ b/assets/js/5bed7376.1106c1a5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[1500],{7091:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"tutorial-basics/method-data-source","title":"Method Data Sources","description":"A limitation of passing data in with [Arguments(...)] is that the data must be constant values. For example, we can\'t new up an object and pass it into this attribute as an argument. This is a constraint of the language and we can\'t change that.","source":"@site/docs/tutorial-basics/method-data-source.md","sourceDirName":"tutorial-basics","slug":"/tutorial-basics/method-data-source","permalink":"/TUnit/docs/tutorial-basics/method-data-source","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"sidebar_position":5},"sidebar":"tutorialSidebar","previous":{"title":"Injectable Class Data Source","permalink":"/TUnit/docs/tutorial-basics/class-data-source"},"next":{"title":"Matrix Tests","permalink":"/TUnit/docs/tutorial-basics/matrix-tests"}}');var a=n(4848),i=n(8453);const o={sidebar_position:5},r="Method Data Sources",c={},d=[];function u(t){const e={code:"code",h1:"h1",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...t.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(e.header,{children:(0,a.jsx)(e.h1,{id:"method-data-sources",children:"Method Data Sources"})}),"\n",(0,a.jsxs)(e.p,{children:["A limitation of passing data in with ",(0,a.jsx)(e.code,{children:"[Arguments(...)]"})," is that the data must be ",(0,a.jsx)(e.code,{children:"constant"})," values. For example, we can't new up an object and pass it into this attribute as an argument. This is a constraint of the language and we can't change that."]}),"\n",(0,a.jsx)(e.p,{children:"If we want test data represented in the form of objects, or just to use something that isn't a constant, we can declare a test data source."}),"\n",(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.code,{children:"MethodDataSource"})," has two options:"]}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsx)(e.li,{children:"If you pass in one argument, this is the method name containing your data. TUnit will assume this is in the current test class."}),"\n",(0,a.jsxs)(e.li,{children:["If you pass in two arguments, the first should be the ",(0,a.jsx)(e.code,{children:"Type"})," of the class containing your test source data method, and the second should be the name of the method."]}),"\n"]}),"\n",(0,a.jsxs)(e.p,{children:["If methods are returning reference types, they should return a ",(0,a.jsx)(e.code,{children:"Func"})," rather than just a ",(0,a.jsx)(e.code,{children:"T"})," - This ensures each test has its own instance of that object and tests aren't sharing objects which could lead to unintended side effects."]}),"\n",(0,a.jsx)(e.p,{children:"Here's an example returning a simple object:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic record AdditionTestData(int Value1, int Value2, int ExpectedResult);\n\npublic static class MyTestDataSources\n{\n public static Func AdditionTestData()\n {\n return () => new AdditionTestData(1, 2, 3);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(AdditionTestData additionTestData)\n {\n var result = Add(additionTestData.Value1, additionTestData.Value2);\n\n await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsx)(e.p,{children:"This can also accept tuples if you don't want to create lots of new types within your test assembly:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic static class MyTestDataSources\n{\n public static Func<(int, int, int)> AdditionTestData()\n {\n return () => (1, 2, 3);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(int value1, int value2, int expectedResult)\n {\n var result = Add(value1, value2);\n\n await Assert.That(result).IsEqualTo(expectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsxs)(e.p,{children:["This attribute can also accept ",(0,a.jsx)(e.code,{children:"IEnumerable<>"}),". For each item returned, a new test will be created with that item passed in to the parameters."]}),"\n",(0,a.jsx)(e.p,{children:"Here's an example where the test would be invoked 3 times:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic record AdditionTestData(int Value1, int Value2, int ExpectedResult);\n\npublic static class MyTestDataSources\n{\n public static IEnumerable> AdditionTestData()\n {\n yield return () => new AdditionTestData(1, 2, 3);\n yield return () => new AdditionTestData(2, 2, 4);\n yield return () => new AdditionTestData(5, 5, 10);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(AdditionTestData additionTestData)\n {\n var result = Add(additionTestData.Value1, additionTestData.Value2);\n\n await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsx)(e.p,{children:"This can also accept tuples if you don't want to create lots of new types within your test assembly:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic static class MyTestDataSources\n{\n public static IEnumerable> AdditionTestData()\n {\n yield return () => (1, 2, 3);\n yield return () => (2, 2, 4);\n yield return () => (5, 5, 10);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(int value1, int value2, int expectedResult)\n {\n var result = Add(value1, value2);\n\n await Assert.That(result).IsEqualTo(expectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})})]})}function l(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};return e?(0,a.jsx)(e,{...t,children:(0,a.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>r});var s=n(6540);const a={},i=s.createContext(a);function o(t){const e=s.useContext(i);return s.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function r(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(a):t.components||a:o(t.components),s.createElement(i.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/5bed7376.923c8349.js b/assets/js/5bed7376.923c8349.js deleted file mode 100644 index 8357a7b453..0000000000 --- a/assets/js/5bed7376.923c8349.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[1500],{7091:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>l,frontMatter:()=>o,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"tutorial-basics/method-data-source","title":"Method Data Sources","description":"A limitation of passing data in with [Arguments(...)] is that the data must be constant values. For example, we can\'t new up an object and pass it into this attribute as an argument. This is a constraint of the language and we can\'t change that.","source":"@site/docs/tutorial-basics/method-data-source.md","sourceDirName":"tutorial-basics","slug":"/tutorial-basics/method-data-source","permalink":"/TUnit/docs/tutorial-basics/method-data-source","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":5,"frontMatter":{"sidebar_position":5},"sidebar":"tutorialSidebar","previous":{"title":"Injectable Class Data Source","permalink":"/TUnit/docs/tutorial-basics/class-data-source"},"next":{"title":"Matrix Tests","permalink":"/TUnit/docs/tutorial-basics/matrix-tests"}}');var a=n(4848),i=n(8453);const o={sidebar_position:5},r="Method Data Sources",c={},d=[];function u(t){const e={code:"code",h1:"h1",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...t.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(e.header,{children:(0,a.jsx)(e.h1,{id:"method-data-sources",children:"Method Data Sources"})}),"\n",(0,a.jsxs)(e.p,{children:["A limitation of passing data in with ",(0,a.jsx)(e.code,{children:"[Arguments(...)]"})," is that the data must be ",(0,a.jsx)(e.code,{children:"constant"})," values. For example, we can't new up an object and pass it into this attribute as an argument. This is a constraint of the language and we can't change that."]}),"\n",(0,a.jsx)(e.p,{children:"If we want test data represented in the form of objects, or just to use something that isn't a constant, we can declare a test data source."}),"\n",(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.code,{children:"MethodDataSource"})," has two options:"]}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsx)(e.li,{children:"If you pass in one argument, this is the method name containing your data. TUnit will assume this is in the current test class."}),"\n",(0,a.jsxs)(e.li,{children:["If you pass in two arguments, the first should be the ",(0,a.jsx)(e.code,{children:"Type"})," of the class containing your test source data method, and the second should be the name of the method."]}),"\n"]}),"\n",(0,a.jsx)(e.p,{children:"Here's an example returning a simple object:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic record AdditionTestData(int Value1, int Value2, int ExpectedResult);\n\npublic static class MyTestDataSources\n{\n public static AdditionTestData AdditionTestData()\n {\n return new AdditionTestData(1, 2, 3);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(AdditionTestData additionTestData)\n {\n var result = Add(additionTestData.Value1, additionTestData.Value2);\n\n await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsx)(e.p,{children:"This can also accept tuples if you don't want to create lots of new types within your test assembly:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic static class MyTestDataSources\n{\n public static (int, int, int) AdditionTestData()\n {\n return (1, 2, 3);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(int value1, int value2, int expectedResult)\n {\n var result = Add(value1, value2);\n\n await Assert.That(result).IsEqualTo(expectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsxs)(e.p,{children:["This attribute can also accept ",(0,a.jsx)(e.code,{children:"IEnumerable<>"}),". For each item returned, a new test will be created with that item passed in to the parameters."]}),"\n",(0,a.jsx)(e.p,{children:"Here's an example where the test would be invoked 3 times:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic record AdditionTestData(int Value1, int Value2, int ExpectedResult);\n\npublic static class MyTestDataSources\n{\n public static IEnumerable AdditionTestData()\n {\n yield return new AdditionTestData(1, 2, 3);\n yield return new AdditionTestData(2, 2, 4);\n yield return new AdditionTestData(5, 5, 10);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(AdditionTestData additionTestData)\n {\n var result = Add(additionTestData.Value1, additionTestData.Value2);\n\n await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})}),"\n",(0,a.jsx)(e.p,{children:"This can also accept tuples if you don't want to create lots of new types within your test assembly:"}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"language-csharp",children:"using TUnit.Assertions;\nusing TUnit.Assertions.Extensions;\nusing TUnit.Core;\n\nnamespace MyTestProject;\n\npublic static class MyTestDataSources\n{\n public static IEnumerable<(int, int, int)> AdditionTestData()\n {\n yield return (1, 2, 3);\n yield return (2, 2, 4);\n yield return (5, 5, 10);\n }\n}\n\npublic class MyTestClass\n{\n [Test]\n [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]\n public async Task MyTest(int value1, int value2, int expectedResult)\n {\n var result = Add(value1, value2);\n\n await Assert.That(result).IsEqualTo(expectedResult);\n }\n\n private int Add(int x, int y)\n {\n return x + y;\n }\n}\n"})})]})}function l(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};return e?(0,a.jsx)(e,{...t,children:(0,a.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>r});var s=n(6540);const a={},i=s.createContext(a);function o(t){const e=s.useContext(i);return s.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function r(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(a):t.components||a:o(t.components),s.createElement(i.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/991d4a8b.308af1bb.js b/assets/js/991d4a8b.308af1bb.js new file mode 100644 index 0000000000..cfa2143816 --- /dev/null +++ b/assets/js/991d4a8b.308af1bb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[6905],{2109:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});const a=JSON.parse('{"id":"tutorial-extras/data-source-generators","title":"Data Source Generators","description":"TUnit exposes an abstract DataSourceGeneratorAttribute class that you can inherit from and implement your own logic for creating values.","source":"@site/docs/tutorial-extras/data-source-generators.md","sourceDirName":"tutorial-extras","slug":"/tutorial-extras/data-source-generators","permalink":"/TUnit/docs/tutorial-extras/data-source-generators","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":13,"frontMatter":{"sidebar_position":13},"sidebar":"tutorialSidebar","previous":{"title":"Command Line Flags","permalink":"/TUnit/docs/tutorial-extras/command-line-flags"},"next":{"title":"Property Injection","permalink":"/TUnit/docs/tutorial-extras/property-injection"}}');var r=n(4848),s=n(8453);const o={sidebar_position:13},i="Data Source Generators",c={},d=[];function l(e){const t={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"data-source-generators",children:"Data Source Generators"})}),"\n",(0,r.jsxs)(t.p,{children:["TUnit exposes an ",(0,r.jsx)(t.code,{children:"abstract"})," ",(0,r.jsx)(t.code,{children:"DataSourceGeneratorAttribute"})," class that you can inherit from and implement your own logic for creating values."]}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.code,{children:"DataSourceGeneratorAttribute"})," class uses generic ",(0,r.jsx)(t.code,{children:"Type"})," arguments to keep your data strongly typed."]}),"\n",(0,r.jsxs)(t.p,{children:["This attribute can be useful to easily populate data in a generic way, and without having to define lots of specific ",(0,r.jsx)(t.code,{children:"MethodDataSources"})]}),"\n",(0,r.jsxs)(t.p,{children:["If you just need to generate data for a single parameter, you simply return ",(0,r.jsx)(t.code,{children:"T"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["If you need to generate data for multiple parameters, you must use a ",(0,r.jsx)(t.code,{children:"Tuple<>"})," return type. E.g. ",(0,r.jsx)(t.code,{children:"return (T1, T2, T3)"})]}),"\n",(0,r.jsx)(t.p,{children:"Here's an example that uses AutoFixture to generate arguments:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"using TUnit.Core;\n\nnamespace MyTestProject;\n\npublic class AutoFixtureGeneratorAttribute : DataSourceGeneratorAttribute\n{\n public override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)\n {\n var fixture = new Fixture();\n \n yield return () => (fixture.Create(), fixture.Create(), fixture.Create());\n }\n}\n\n[AutoFixtureGenerator]\npublic class MyTestClass(SomeClass1 someClass1, SomeClass2 someClass2, SomeClass3 someClass3)\n{\n [Test]\n [AutoFixtureGenerator]\n public async Task Test((int value, string value2, bool value3))\n {\n // ...\n }\n}\n\n\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Notes:\n",(0,r.jsx)(t.code,{children:"GenerateDataSources()"})," could be called multiple times if you have nested loops to generate data within your tests. Because of this, you are required to return a ",(0,r.jsx)(t.code,{children:"Func"})," - This means that tests can create a new object each time for a test case. Otherwise, we'd be pointing to the same object if we were in a nested loop and that could lead to unintended side-effects."]}),"\n",(0,r.jsx)(t.p,{children:"An example could be using a DataSourceGenerator on both the class and the test method, resulting with a loop within a loop."}),"\n",(0,r.jsx)(t.p,{children:"Because this could be called multiple times, if you're subscribing to test events and storing state within the attribute, be aware of this and how this could affect disposal etc."}),"\n",(0,r.jsxs)(t.p,{children:["Instead, you can use the ",(0,r.jsx)(t.code,{children:"yield return"})," pattern, and use the ",(0,r.jsx)(t.code,{children:"TestBuilderContext"})," from the ",(0,r.jsx)(t.code,{children:"DataGeneratorMetadata"})," object passed to you.\nAfter each ",(0,r.jsx)(t.code,{children:"yield"}),", the execution is passed back to TUnit, and TUnit will set a new ",(0,r.jsx)(t.code,{children:"TestBuilderContext"})," for you - So as long as you yield each result, you'll get a unique context object for each test case.\nThe ",(0,r.jsx)(t.code,{children:"TestBuilderContext"})," object exposes ",(0,r.jsx)(t.code,{children:"Events"})," - And you can register a delegate to be invoked on them at the point in the test lifecycle that you wish."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-csharp",children:"\n public override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)\n {\n dataGeneratorMetadata.TestBuilderContext.Current; // <-- Initial Context for first test\n \n yield return () => 1;\n \n dataGeneratorMetadata.TestBuilderContext.Current; // <-- This is now a different context object, as we yielded\n dataGeneratorMetadata.TestBuilderContext.Current; // <-- This is still the same as above because it'll only change on a yield\n \n yield return () => 2;\n \n dataGeneratorMetadata.TestBuilderContext.Current; // <-- A new object again\n }\n\n"})})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>i});var a=n(6540);const r={},s=a.createContext(r);function o(e){const t=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/991d4a8b.a0ac7e86.js b/assets/js/991d4a8b.a0ac7e86.js deleted file mode 100644 index 1e5e884072..0000000000 --- a/assets/js/991d4a8b.a0ac7e86.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[6905],{2109:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>n,toc:()=>u});const n=JSON.parse('{"id":"tutorial-extras/data-source-generators","title":"Data Source Generators","description":"TUnit exposes an abstract DataSourceGeneratorAttribute class that you can inherit from and implement your own logic for creating values.","source":"@site/docs/tutorial-extras/data-source-generators.md","sourceDirName":"tutorial-extras","slug":"/tutorial-extras/data-source-generators","permalink":"/TUnit/docs/tutorial-extras/data-source-generators","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":13,"frontMatter":{"sidebar_position":13},"sidebar":"tutorialSidebar","previous":{"title":"Command Line Flags","permalink":"/TUnit/docs/tutorial-extras/command-line-flags"},"next":{"title":"Property Injection","permalink":"/TUnit/docs/tutorial-extras/property-injection"}}');var a=r(4848),s=r(8453);const o={sidebar_position:13},i="Data Source Generators",c={},u=[];function l(e){const t={code:"code",h1:"h1",header:"header",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.header,{children:(0,a.jsx)(t.h1,{id:"data-source-generators",children:"Data Source Generators"})}),"\n",(0,a.jsxs)(t.p,{children:["TUnit exposes an ",(0,a.jsx)(t.code,{children:"abstract"})," ",(0,a.jsx)(t.code,{children:"DataSourceGeneratorAttribute"})," class that you can inherit from and implement your own logic for creating values."]}),"\n",(0,a.jsxs)(t.p,{children:["The ",(0,a.jsx)(t.code,{children:"DataSourceGeneratorAttribute"})," class uses generic ",(0,a.jsx)(t.code,{children:"Type"})," arguments to keep your data strongly typed."]}),"\n",(0,a.jsxs)(t.p,{children:["This attribute can be useful to easily populate data in a generic way, and without having to define lots of specific ",(0,a.jsx)(t.code,{children:"MethodDataSources"})]}),"\n",(0,a.jsxs)(t.p,{children:["If you just need to generate data for a single parameter, you simply return ",(0,a.jsx)(t.code,{children:"T"}),"."]}),"\n",(0,a.jsxs)(t.p,{children:["If you need to generate data for multiple parameters, you must use a ",(0,a.jsx)(t.code,{children:"Tuple<>"})," return type. E.g. ",(0,a.jsx)(t.code,{children:"return (T1, T2, T3)"})]}),"\n",(0,a.jsx)(t.p,{children:"Here's an example that uses AutoFixture to generate arguments:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-csharp",children:"using TUnit.Core;\n\nnamespace MyTestProject;\n\npublic class AutoFixtureGeneratorAttribute : DataSourceGeneratorAttribute\n{\n public override IEnumerable<(T1, T2, T3)> GenerateDataSources()\n {\n var fixture = new Fixture();\n \n yield return (fixture.Create(), fixture.Create(), fixture.Create());\n }\n}\n\n[AutoFixtureGenerator]\npublic class MyTestClass(SomeClass1 someClass1, SomeClass2 someClass2, SomeClass3 someClass3)\n{\n [Test]\n [AutoFixtureGenerator]\n public async Task Test((int value, string value2, bool value3))\n {\n // ...\n }\n}\n"})})]})}function d(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(l,{...e})}):l(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>i});var n=r(6540);const a={},s=n.createContext(a);function o(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:o(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.1b7d8497.js b/assets/js/runtime~main.078fc227.js similarity index 68% rename from assets/js/runtime~main.1b7d8497.js rename to assets/js/runtime~main.078fc227.js index db15e769a2..4e11fae001 100644 --- a/assets/js/runtime~main.1b7d8497.js +++ b/assets/js/runtime~main.078fc227.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,d,b,r={},f={};function c(e){var a=f[e];if(void 0!==a)return a.exports;var t=f[e]={exports:{}};return r[e].call(t.exports,t,t.exports,c),t.exports}c.m=r,e=[],c.O=(a,t,d,b)=>{if(!t){var r=1/0;for(i=0;i=b)&&Object.keys(c.O).every((e=>c.O[e](t[o])))?t.splice(o--,1):(f=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[t,d,b]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var b=Object.create(null);c.r(b);var r={};a=a||[null,t({}),t([]),t(t)];for(var f=2&d&&e;"object"==typeof f&&!~a.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,c.d(b,r),b},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((a,t)=>(c.f[t](e,a),a)),[])),c.u=e=>"assets/js/"+({568:"26e4ff2b",570:"91d5c99e",1114:"e322696d",1235:"a7456010",1500:"5bed7376",1647:"b1a8519a",1745:"e9b3e67e",1747:"f7b7b503",2225:"4b18aed1",2321:"ba8db043",2473:"b3030475",2590:"8ff4cdb2",2748:"822bd8ab",2801:"6694e4aa",2984:"c566dcac",3398:"8b1309c7",3487:"60a9c782",3604:"5c580d35",3818:"7c0d1a7d",3976:"0e384e19",4031:"465fdebd",4134:"393be207",4298:"13e939a4",4583:"1df93b7f",4761:"13f17bf8",4956:"e10a8de7",5385:"49aa2eea",5742:"aba21aa0",5770:"6a12013c",5803:"f08d5324",6061:"1f391b9e",6168:"49462f00",6220:"5dbdde90",6458:"58d4c641",6532:"914d3ab3",6538:"a34b2a44",6617:"cb1d92ed",6866:"73e1c817",6905:"991d4a8b",6969:"14eb3368",7098:"a7bd4aaa",7326:"e1f02bbc",7543:"55c176cd",7564:"2a9ef78c",7846:"be2154f8",7969:"4c5555c4",8401:"17896441",8584:"ba7c896e",8642:"9f69b8de",8715:"d3238b2f",8732:"8b247495",8887:"12f8ba17",9048:"a94703ab",9069:"3609cdcd",9081:"85aaec92",9132:"4c362b47",9372:"a66eab3e",9647:"5e95c892",9814:"6a21048e"}[e]||e)+"."+{568:"59a5f9ab",570:"7bc3e163",1114:"52a476bb",1235:"1b4d7e11",1500:"923c8349",1647:"282cd2cd",1745:"c17d7ec8",1747:"d9dea6b6",2225:"e0d68166",2321:"2fe09cf5",2473:"9991e0ba",2590:"288996e6",2748:"6cf4d69f",2801:"5ebefda6",2984:"7f995684",3398:"ccb4e2cf",3487:"a5690efe",3604:"d8ad35b6",3726:"544231b5",3818:"a1ea5e0e",3976:"6b209be7",4031:"23f53119",4134:"a8ee41a2",4298:"47b824e8",4583:"76d773b2",4761:"59505765",4896:"25b1cf94",4956:"1bdbd5cd",5385:"d15be81b",5742:"f183b5b5",5770:"a7355ae5",5803:"2cf0923a",6061:"71161e3c",6168:"53d33f4c",6220:"f2e6cf4b",6458:"f186202b",6532:"8a28ec75",6538:"64173a6c",6617:"27f14287",6866:"aecc372e",6905:"a0ac7e86",6969:"5e588021",7098:"cf78a617",7326:"57d13ab0",7543:"67a1bd21",7564:"d27b2e18",7846:"6b58fcd9",7969:"c0a83f77",8401:"953f2b9e",8584:"239ce384",8642:"75ad662a",8715:"12da10ac",8732:"bfbbc24c",8887:"4900363b",9048:"ce20f8b2",9069:"b684f686",9081:"83fb30ba",9132:"be9fcd41",9372:"453f4f9a",9647:"1d40b763",9814:"5adf3f51"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},b="tunit-docs-site:",c.l=(e,a,t,r)=>{if(d[e])d[e].push(a);else{var f,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{f.onerror=f.onload=null,clearTimeout(s);var b=d[e];if(delete d[e],f.parentNode&&f.parentNode.removeChild(f),b&&b.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),o&&document.head.appendChild(f)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/TUnit/",c.gca=function(e){return e={17896441:"8401","26e4ff2b":"568","91d5c99e":"570",e322696d:"1114",a7456010:"1235","5bed7376":"1500",b1a8519a:"1647",e9b3e67e:"1745",f7b7b503:"1747","4b18aed1":"2225",ba8db043:"2321",b3030475:"2473","8ff4cdb2":"2590","822bd8ab":"2748","6694e4aa":"2801",c566dcac:"2984","8b1309c7":"3398","60a9c782":"3487","5c580d35":"3604","7c0d1a7d":"3818","0e384e19":"3976","465fdebd":"4031","393be207":"4134","13e939a4":"4298","1df93b7f":"4583","13f17bf8":"4761",e10a8de7:"4956","49aa2eea":"5385",aba21aa0:"5742","6a12013c":"5770",f08d5324:"5803","1f391b9e":"6061","49462f00":"6168","5dbdde90":"6220","58d4c641":"6458","914d3ab3":"6532",a34b2a44:"6538",cb1d92ed:"6617","73e1c817":"6866","991d4a8b":"6905","14eb3368":"6969",a7bd4aaa:"7098",e1f02bbc:"7326","55c176cd":"7543","2a9ef78c":"7564",be2154f8:"7846","4c5555c4":"7969",ba7c896e:"8584","9f69b8de":"8642",d3238b2f:"8715","8b247495":"8732","12f8ba17":"8887",a94703ab:"9048","3609cdcd":"9069","85aaec92":"9081","4c362b47":"9132",a66eab3e:"9372","5e95c892":"9647","6a21048e":"9814"}[e]||e,c.p+c.u(e)},(()=>{var e={5354:0,1869:0};c.f.j=(a,t)=>{var d=c.o(e,a)?e[a]:void 0;if(0!==d)if(d)t.push(d[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var b=new Promise(((t,b)=>d=e[a]=[t,b]));t.push(d[2]=b);var r=c.p+c.u(a),f=new Error;c.l(r,(t=>{if(c.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var b=t&&("load"===t.type?"missing":t.type),r=t&&t.target&&t.target.src;f.message="Loading chunk "+a+" failed.\n("+b+": "+r+")",f.name="ChunkLoadError",f.type=b,f.request=r,d[1](f)}}),"chunk-"+a,a)}},c.O.j=a=>0===e[a];var a=(a,t)=>{var d,b,r=t[0],f=t[1],o=t[2],n=0;if(r.some((a=>0!==e[a]))){for(d in f)c.o(f,d)&&(c.m[d]=f[d]);if(o)var i=o(c)}for(a&&a(t);n{"use strict";var e,a,t,b,d,r={},f={};function c(e){var a=f[e];if(void 0!==a)return a.exports;var t=f[e]={exports:{}};return r[e].call(t.exports,t,t.exports,c),t.exports}c.m=r,e=[],c.O=(a,t,b,d)=>{if(!t){var r=1/0;for(i=0;i=d)&&Object.keys(c.O).every((e=>c.O[e](t[o])))?t.splice(o--,1):(f=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[t,b,d]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var d=Object.create(null);c.r(d);var r={};a=a||[null,t({}),t([]),t(t)];for(var f=2&b&&e;"object"==typeof f&&!~a.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,c.d(d,r),d},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((a,t)=>(c.f[t](e,a),a)),[])),c.u=e=>"assets/js/"+({568:"26e4ff2b",570:"91d5c99e",1114:"e322696d",1235:"a7456010",1500:"5bed7376",1647:"b1a8519a",1745:"e9b3e67e",1747:"f7b7b503",2225:"4b18aed1",2321:"ba8db043",2473:"b3030475",2590:"8ff4cdb2",2748:"822bd8ab",2801:"6694e4aa",2984:"c566dcac",3398:"8b1309c7",3487:"60a9c782",3604:"5c580d35",3818:"7c0d1a7d",3976:"0e384e19",4031:"465fdebd",4134:"393be207",4298:"13e939a4",4583:"1df93b7f",4761:"13f17bf8",4956:"e10a8de7",5385:"49aa2eea",5742:"aba21aa0",5770:"6a12013c",5803:"f08d5324",6061:"1f391b9e",6168:"49462f00",6220:"5dbdde90",6458:"58d4c641",6532:"914d3ab3",6538:"a34b2a44",6617:"cb1d92ed",6866:"73e1c817",6905:"991d4a8b",6969:"14eb3368",7098:"a7bd4aaa",7326:"e1f02bbc",7543:"55c176cd",7564:"2a9ef78c",7846:"be2154f8",7969:"4c5555c4",8401:"17896441",8584:"ba7c896e",8642:"9f69b8de",8715:"d3238b2f",8732:"8b247495",8887:"12f8ba17",9048:"a94703ab",9069:"3609cdcd",9081:"85aaec92",9132:"4c362b47",9372:"a66eab3e",9647:"5e95c892",9814:"6a21048e"}[e]||e)+"."+{568:"59a5f9ab",570:"7bc3e163",1114:"52a476bb",1235:"1b4d7e11",1500:"1106c1a5",1647:"282cd2cd",1745:"c17d7ec8",1747:"d9dea6b6",2225:"e0d68166",2321:"2fe09cf5",2473:"9991e0ba",2590:"288996e6",2748:"6cf4d69f",2801:"5ebefda6",2984:"7f995684",3398:"ccb4e2cf",3487:"a5690efe",3604:"d8ad35b6",3726:"544231b5",3818:"a1ea5e0e",3976:"6b209be7",4031:"23f53119",4134:"a8ee41a2",4298:"47b824e8",4583:"76d773b2",4761:"59505765",4896:"25b1cf94",4956:"1bdbd5cd",5385:"d15be81b",5742:"f183b5b5",5770:"a7355ae5",5803:"2cf0923a",6061:"71161e3c",6168:"53d33f4c",6220:"f2e6cf4b",6458:"f186202b",6532:"8a28ec75",6538:"64173a6c",6617:"27f14287",6866:"aecc372e",6905:"308af1bb",6969:"5e588021",7098:"cf78a617",7326:"57d13ab0",7543:"67a1bd21",7564:"d27b2e18",7846:"6b58fcd9",7969:"c0a83f77",8401:"953f2b9e",8584:"239ce384",8642:"75ad662a",8715:"12da10ac",8732:"bfbbc24c",8887:"4900363b",9048:"ce20f8b2",9069:"b684f686",9081:"83fb30ba",9132:"be9fcd41",9372:"453f4f9a",9647:"1d40b763",9814:"5adf3f51"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),b={},d="tunit-docs-site:",c.l=(e,a,t,r)=>{if(b[e])b[e].push(a);else{var f,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{f.onerror=f.onload=null,clearTimeout(s);var d=b[e];if(delete b[e],f.parentNode&&f.parentNode.removeChild(f),d&&d.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),o&&document.head.appendChild(f)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/TUnit/",c.gca=function(e){return e={17896441:"8401","26e4ff2b":"568","91d5c99e":"570",e322696d:"1114",a7456010:"1235","5bed7376":"1500",b1a8519a:"1647",e9b3e67e:"1745",f7b7b503:"1747","4b18aed1":"2225",ba8db043:"2321",b3030475:"2473","8ff4cdb2":"2590","822bd8ab":"2748","6694e4aa":"2801",c566dcac:"2984","8b1309c7":"3398","60a9c782":"3487","5c580d35":"3604","7c0d1a7d":"3818","0e384e19":"3976","465fdebd":"4031","393be207":"4134","13e939a4":"4298","1df93b7f":"4583","13f17bf8":"4761",e10a8de7:"4956","49aa2eea":"5385",aba21aa0:"5742","6a12013c":"5770",f08d5324:"5803","1f391b9e":"6061","49462f00":"6168","5dbdde90":"6220","58d4c641":"6458","914d3ab3":"6532",a34b2a44:"6538",cb1d92ed:"6617","73e1c817":"6866","991d4a8b":"6905","14eb3368":"6969",a7bd4aaa:"7098",e1f02bbc:"7326","55c176cd":"7543","2a9ef78c":"7564",be2154f8:"7846","4c5555c4":"7969",ba7c896e:"8584","9f69b8de":"8642",d3238b2f:"8715","8b247495":"8732","12f8ba17":"8887",a94703ab:"9048","3609cdcd":"9069","85aaec92":"9081","4c362b47":"9132",a66eab3e:"9372","5e95c892":"9647","6a21048e":"9814"}[e]||e,c.p+c.u(e)},(()=>{var e={5354:0,1869:0};c.f.j=(a,t)=>{var b=c.o(e,a)?e[a]:void 0;if(0!==b)if(b)t.push(b[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var d=new Promise(((t,d)=>b=e[a]=[t,d]));t.push(b[2]=d);var r=c.p+c.u(a),f=new Error;c.l(r,(t=>{if(c.o(e,a)&&(0!==(b=e[a])&&(e[a]=void 0),b)){var d=t&&("load"===t.type?"missing":t.type),r=t&&t.target&&t.target.src;f.message="Loading chunk "+a+" failed.\n("+d+": "+r+")",f.name="ChunkLoadError",f.type=d,f.request=r,b[1](f)}}),"chunk-"+a,a)}},c.O.j=a=>0===e[a];var a=(a,t)=>{var b,d,r=t[0],f=t[1],o=t[2],n=0;if(r.some((a=>0!==e[a]))){for(b in f)c.o(f,b)&&(c.m[b]=f[b]);if(o)var i=o(c)}for(a&&a(t);n Extensions | TUnit - + diff --git a/docs/category/test-framework-comparisons/index.html b/docs/category/test-framework-comparisons/index.html index 7dc78cf688..84d45a2019 100644 --- a/docs/category/test-framework-comparisons/index.html +++ b/docs/category/test-framework-comparisons/index.html @@ -4,7 +4,7 @@ Test Framework Comparisons | TUnit - + diff --git a/docs/category/tutorial---assertions/index.html b/docs/category/tutorial---assertions/index.html index 98448cc7b8..d4cf9f8f4e 100644 --- a/docs/category/tutorial---assertions/index.html +++ b/docs/category/tutorial---assertions/index.html @@ -4,7 +4,7 @@ Tutorial - Assertions | TUnit - + diff --git a/docs/category/tutorial---basics/index.html b/docs/category/tutorial---basics/index.html index bbb6dbae83..c0f03f1a75 100644 --- a/docs/category/tutorial---basics/index.html +++ b/docs/category/tutorial---basics/index.html @@ -4,7 +4,7 @@ Tutorial - Basics | TUnit - + diff --git a/docs/category/tutorial---extras/index.html b/docs/category/tutorial---extras/index.html index 3137f3623f..be6cf4f54e 100644 --- a/docs/category/tutorial---extras/index.html +++ b/docs/category/tutorial---extras/index.html @@ -4,7 +4,7 @@ Tutorial - Extras | TUnit - + diff --git a/docs/comparison/attributes/index.html b/docs/comparison/attributes/index.html index e52840928d..c5cf0852dd 100644 --- a/docs/comparison/attributes/index.html +++ b/docs/comparison/attributes/index.html @@ -4,7 +4,7 @@ Attributes | TUnit - + diff --git a/docs/comparison/framework-differences/index.html b/docs/comparison/framework-differences/index.html index 93531943f9..e44bc79707 100644 --- a/docs/comparison/framework-differences/index.html +++ b/docs/comparison/framework-differences/index.html @@ -4,7 +4,7 @@ Framework Differences | TUnit - + diff --git a/docs/extensions/index.html b/docs/extensions/index.html index 23aa32ab8c..8a5d5dbebd 100644 --- a/docs/extensions/index.html +++ b/docs/extensions/index.html @@ -4,7 +4,7 @@ Extensions | TUnit - + diff --git a/docs/intro/index.html b/docs/intro/index.html index 8457b4aa17..a5b1934c70 100644 --- a/docs/intro/index.html +++ b/docs/intro/index.html @@ -4,7 +4,7 @@ Intro | TUnit - + diff --git a/docs/tutorial-assertions/and-conditions/index.html b/docs/tutorial-assertions/and-conditions/index.html index a90aac41d5..dae8e3f673 100644 --- a/docs/tutorial-assertions/and-conditions/index.html +++ b/docs/tutorial-assertions/and-conditions/index.html @@ -4,7 +4,7 @@ And Conditions | TUnit - + diff --git a/docs/tutorial-assertions/assertion-groups/index.html b/docs/tutorial-assertions/assertion-groups/index.html index c2ae8f09e7..de697a73b4 100644 --- a/docs/tutorial-assertions/assertion-groups/index.html +++ b/docs/tutorial-assertions/assertion-groups/index.html @@ -4,7 +4,7 @@ Assertion Groups | TUnit - + diff --git a/docs/tutorial-assertions/awaiting/index.html b/docs/tutorial-assertions/awaiting/index.html index 26298169eb..38dc17aad0 100644 --- a/docs/tutorial-assertions/awaiting/index.html +++ b/docs/tutorial-assertions/awaiting/index.html @@ -4,7 +4,7 @@ Awaiting | TUnit - + diff --git a/docs/tutorial-assertions/congratulations/index.html b/docs/tutorial-assertions/congratulations/index.html index c20c503e68..255f510066 100644 --- a/docs/tutorial-assertions/congratulations/index.html +++ b/docs/tutorial-assertions/congratulations/index.html @@ -4,7 +4,7 @@ Congratulations | TUnit - + diff --git a/docs/tutorial-assertions/delegates/index.html b/docs/tutorial-assertions/delegates/index.html index 0d26b7e984..fa06219362 100644 --- a/docs/tutorial-assertions/delegates/index.html +++ b/docs/tutorial-assertions/delegates/index.html @@ -4,7 +4,7 @@ Delegates | TUnit - + diff --git a/docs/tutorial-assertions/extensibility/index.html b/docs/tutorial-assertions/extensibility/index.html index e54c9204e8..d594a2b04e 100644 --- a/docs/tutorial-assertions/extensibility/index.html +++ b/docs/tutorial-assertions/extensibility/index.html @@ -4,7 +4,7 @@ Extensibility / Custom Assertions | TUnit - + diff --git a/docs/tutorial-assertions/or-conditions/index.html b/docs/tutorial-assertions/or-conditions/index.html index 1711626b2b..da70c159c9 100644 --- a/docs/tutorial-assertions/or-conditions/index.html +++ b/docs/tutorial-assertions/or-conditions/index.html @@ -4,7 +4,7 @@ Or Conditions | TUnit - + diff --git a/docs/tutorial-assertions/scopes/index.html b/docs/tutorial-assertions/scopes/index.html index d092c7da2b..850682c65e 100644 --- a/docs/tutorial-assertions/scopes/index.html +++ b/docs/tutorial-assertions/scopes/index.html @@ -4,7 +4,7 @@ Assertion Scopes | TUnit - + diff --git a/docs/tutorial-assertions/type-checking/index.html b/docs/tutorial-assertions/type-checking/index.html index ae51a7ea56..a8bdb3df85 100644 --- a/docs/tutorial-assertions/type-checking/index.html +++ b/docs/tutorial-assertions/type-checking/index.html @@ -4,7 +4,7 @@ Type Checking | TUnit - + diff --git a/docs/tutorial-basics/class-data-source/index.html b/docs/tutorial-basics/class-data-source/index.html index b6bd47bcf8..b786f2d541 100644 --- a/docs/tutorial-basics/class-data-source/index.html +++ b/docs/tutorial-basics/class-data-source/index.html @@ -4,7 +4,7 @@ Injectable Class Data Source | TUnit - + diff --git a/docs/tutorial-basics/congratulations/index.html b/docs/tutorial-basics/congratulations/index.html index 823a12b20b..70d2340d43 100644 --- a/docs/tutorial-basics/congratulations/index.html +++ b/docs/tutorial-basics/congratulations/index.html @@ -4,7 +4,7 @@ Congratulations! | TUnit - + diff --git a/docs/tutorial-basics/data-driven-tests/index.html b/docs/tutorial-basics/data-driven-tests/index.html index 31f3c0ca8e..6318616a2c 100644 --- a/docs/tutorial-basics/data-driven-tests/index.html +++ b/docs/tutorial-basics/data-driven-tests/index.html @@ -4,7 +4,7 @@ Data Driven Tests | TUnit - + diff --git a/docs/tutorial-basics/installing/index.html b/docs/tutorial-basics/installing/index.html index 5cbd61387e..0734182f18 100644 --- a/docs/tutorial-basics/installing/index.html +++ b/docs/tutorial-basics/installing/index.html @@ -4,7 +4,7 @@ Installing TUnit | TUnit - + diff --git a/docs/tutorial-basics/libraries/index.html b/docs/tutorial-basics/libraries/index.html index 9830b419f8..c878501873 100644 --- a/docs/tutorial-basics/libraries/index.html +++ b/docs/tutorial-basics/libraries/index.html @@ -4,7 +4,7 @@ Libraries | TUnit - + diff --git a/docs/tutorial-basics/matrix-tests/index.html b/docs/tutorial-basics/matrix-tests/index.html index ed724a3525..ed16d291f5 100644 --- a/docs/tutorial-basics/matrix-tests/index.html +++ b/docs/tutorial-basics/matrix-tests/index.html @@ -4,7 +4,7 @@ Matrix Tests | TUnit - + diff --git a/docs/tutorial-basics/method-data-source/index.html b/docs/tutorial-basics/method-data-source/index.html index 54580bedd8..29f6ad2936 100644 --- a/docs/tutorial-basics/method-data-source/index.html +++ b/docs/tutorial-basics/method-data-source/index.html @@ -4,7 +4,7 @@ Method Data Sources | TUnit - + @@ -16,14 +16,15 @@
  • If you pass in one argument, this is the method name containing your data. TUnit will assume this is in the current test class.
  • If you pass in two arguments, the first should be the Type of the class containing your test source data method, and the second should be the name of the method.
  • +

    If methods are returning reference types, they should return a Func<T> rather than just a T - This ensures each test has its own instance of that object and tests aren't sharing objects which could lead to unintended side effects.

    Here's an example returning a simple object:

    -
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public record AdditionTestData(int Value1, int Value2, int ExpectedResult);

    public static class MyTestDataSources
    {
    public static AdditionTestData AdditionTestData()
    {
    return new AdditionTestData(1, 2, 3);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(AdditionTestData additionTestData)
    {
    var result = Add(additionTestData.Value1, additionTestData.Value2);

    await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }
    +
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public record AdditionTestData(int Value1, int Value2, int ExpectedResult);

    public static class MyTestDataSources
    {
    public static Func<AdditionTestData> AdditionTestData()
    {
    return () => new AdditionTestData(1, 2, 3);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(AdditionTestData additionTestData)
    {
    var result = Add(additionTestData.Value1, additionTestData.Value2);

    await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }

    This can also accept tuples if you don't want to create lots of new types within your test assembly:

    -
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public static class MyTestDataSources
    {
    public static (int, int, int) AdditionTestData()
    {
    return (1, 2, 3);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(int value1, int value2, int expectedResult)
    {
    var result = Add(value1, value2);

    await Assert.That(result).IsEqualTo(expectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }
    +
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public static class MyTestDataSources
    {
    public static Func<(int, int, int)> AdditionTestData()
    {
    return () => (1, 2, 3);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(int value1, int value2, int expectedResult)
    {
    var result = Add(value1, value2);

    await Assert.That(result).IsEqualTo(expectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }

    This attribute can also accept IEnumerable<>. For each item returned, a new test will be created with that item passed in to the parameters.

    Here's an example where the test would be invoked 3 times:

    -
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public record AdditionTestData(int Value1, int Value2, int ExpectedResult);

    public static class MyTestDataSources
    {
    public static IEnumerable<AdditionTestData> AdditionTestData()
    {
    yield return new AdditionTestData(1, 2, 3);
    yield return new AdditionTestData(2, 2, 4);
    yield return new AdditionTestData(5, 5, 10);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(AdditionTestData additionTestData)
    {
    var result = Add(additionTestData.Value1, additionTestData.Value2);

    await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }
    +
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public record AdditionTestData(int Value1, int Value2, int ExpectedResult);

    public static class MyTestDataSources
    {
    public static IEnumerable<Func<AdditionTestData>> AdditionTestData()
    {
    yield return () => new AdditionTestData(1, 2, 3);
    yield return () => new AdditionTestData(2, 2, 4);
    yield return () => new AdditionTestData(5, 5, 10);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(AdditionTestData additionTestData)
    {
    var result = Add(additionTestData.Value1, additionTestData.Value2);

    await Assert.That(result).IsEqualTo(additionTestData.ExpectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }

    This can also accept tuples if you don't want to create lots of new types within your test assembly:

    -
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public static class MyTestDataSources
    {
    public static IEnumerable<(int, int, int)> AdditionTestData()
    {
    yield return (1, 2, 3);
    yield return (2, 2, 4);
    yield return (5, 5, 10);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(int value1, int value2, int expectedResult)
    {
    var result = Add(value1, value2);

    await Assert.That(result).IsEqualTo(expectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }
    +
    using TUnit.Assertions;
    using TUnit.Assertions.Extensions;
    using TUnit.Core;

    namespace MyTestProject;

    public static class MyTestDataSources
    {
    public static IEnumerable<Func<(int, int, int)>> AdditionTestData()
    {
    yield return () => (1, 2, 3);
    yield return () => (2, 2, 4);
    yield return () => (5, 5, 10);
    }
    }

    public class MyTestClass
    {
    [Test]
    [MethodDataSource(typeof(MyTestDataSources), nameof(MyTestDataSources.AdditionTestData))]
    public async Task MyTest(int value1, int value2, int expectedResult)
    {
    var result = Add(value1, value2);

    await Assert.That(result).IsEqualTo(expectedResult);
    }

    private int Add(int x, int y)
    {
    return x + y;
    }
    }
    \ No newline at end of file diff --git a/docs/tutorial-basics/running-your-tests/index.html b/docs/tutorial-basics/running-your-tests/index.html index 2096d8abfc..7f44fc5295 100644 --- a/docs/tutorial-basics/running-your-tests/index.html +++ b/docs/tutorial-basics/running-your-tests/index.html @@ -4,7 +4,7 @@ Running your tests | TUnit - + diff --git a/docs/tutorial-basics/things-to-know/index.html b/docs/tutorial-basics/things-to-know/index.html index 4886ddc37d..de1c38c75c 100644 --- a/docs/tutorial-basics/things-to-know/index.html +++ b/docs/tutorial-basics/things-to-know/index.html @@ -4,7 +4,7 @@ Things to know | TUnit - + diff --git a/docs/tutorial-basics/writing-your-first-test/index.html b/docs/tutorial-basics/writing-your-first-test/index.html index 9f969bab6b..8492d6bb06 100644 --- a/docs/tutorial-basics/writing-your-first-test/index.html +++ b/docs/tutorial-basics/writing-your-first-test/index.html @@ -4,7 +4,7 @@ Writing your first test | TUnit - + diff --git a/docs/tutorial-extras/class-constructors/index.html b/docs/tutorial-extras/class-constructors/index.html index 6103198f8e..da0ddadfac 100644 --- a/docs/tutorial-extras/class-constructors/index.html +++ b/docs/tutorial-extras/class-constructors/index.html @@ -4,7 +4,7 @@ Class Constructor Helpers | TUnit - + diff --git a/docs/tutorial-extras/cleanup/index.html b/docs/tutorial-extras/cleanup/index.html index 15150c08a1..a23572fea3 100644 --- a/docs/tutorial-extras/cleanup/index.html +++ b/docs/tutorial-extras/cleanup/index.html @@ -4,7 +4,7 @@ Test Clean Ups | TUnit - + diff --git a/docs/tutorial-extras/command-line-flags/index.html b/docs/tutorial-extras/command-line-flags/index.html index c2ea0cbc48..1f9f60710e 100644 --- a/docs/tutorial-extras/command-line-flags/index.html +++ b/docs/tutorial-extras/command-line-flags/index.html @@ -4,7 +4,7 @@ Command Line Flags | TUnit - + diff --git a/docs/tutorial-extras/data-source-generators/index.html b/docs/tutorial-extras/data-source-generators/index.html index fa7e8b6e66..4de86574e0 100644 --- a/docs/tutorial-extras/data-source-generators/index.html +++ b/docs/tutorial-extras/data-source-generators/index.html @@ -4,7 +4,7 @@ Data Source Generators | TUnit - + @@ -15,6 +15,14 @@

    If you just need to generate data for a single parameter, you simply return T.

    If you need to generate data for multiple parameters, you must use a Tuple<> return type. E.g. return (T1, T2, T3)

    Here's an example that uses AutoFixture to generate arguments:

    -
    using TUnit.Core;

    namespace MyTestProject;

    public class AutoFixtureGeneratorAttribute<T1, T2, T3> : DataSourceGeneratorAttribute<T1, T2, T3>
    {
    public override IEnumerable<(T1, T2, T3)> GenerateDataSources()
    {
    var fixture = new Fixture();

    yield return (fixture.Create<T1>(), fixture.Create<T2>(), fixture.Create<T3>());
    }
    }

    [AutoFixtureGenerator<SomeClass1, SomeClass2, SomeClass3>]
    public class MyTestClass(SomeClass1 someClass1, SomeClass2 someClass2, SomeClass3 someClass3)
    {
    [Test]
    [AutoFixtureGenerator<int, string, bool>]
    public async Task Test((int value, string value2, bool value3))
    {
    // ...
    }
    }
    +
    using TUnit.Core;

    namespace MyTestProject;

    public class AutoFixtureGeneratorAttribute<T1, T2, T3> : DataSourceGeneratorAttribute<T1, T2, T3>
    {
    public override IEnumerable<Func<(T1, T2, T3)>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)
    {
    var fixture = new Fixture();

    yield return () => (fixture.Create<T1>(), fixture.Create<T2>(), fixture.Create<T3>());
    }
    }

    [AutoFixtureGenerator<SomeClass1, SomeClass2, SomeClass3>]
    public class MyTestClass(SomeClass1 someClass1, SomeClass2 someClass2, SomeClass3 someClass3)
    {
    [Test]
    [AutoFixtureGenerator<int, string, bool>]
    public async Task Test((int value, string value2, bool value3))
    {
    // ...
    }
    }


    +

    Notes: +GenerateDataSources() could be called multiple times if you have nested loops to generate data within your tests. Because of this, you are required to return a Func - This means that tests can create a new object each time for a test case. Otherwise, we'd be pointing to the same object if we were in a nested loop and that could lead to unintended side-effects.

    +

    An example could be using a DataSourceGenerator on both the class and the test method, resulting with a loop within a loop.

    +

    Because this could be called multiple times, if you're subscribing to test events and storing state within the attribute, be aware of this and how this could affect disposal etc.

    +

    Instead, you can use the yield return pattern, and use the TestBuilderContext from the DataGeneratorMetadata object passed to you. +After each yield, the execution is passed back to TUnit, and TUnit will set a new TestBuilderContext for you - So as long as you yield each result, you'll get a unique context object for each test case. +The TestBuilderContext object exposes Events - And you can register a delegate to be invoked on them at the point in the test lifecycle that you wish.

    +

    public override IEnumerable<Func<int>> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata)
    {
    dataGeneratorMetadata.TestBuilderContext.Current; // <-- Initial Context for first test

    yield return () => 1;

    dataGeneratorMetadata.TestBuilderContext.Current; // <-- This is now a different context object, as we yielded
    dataGeneratorMetadata.TestBuilderContext.Current; // <-- This is still the same as above because it'll only change on a yield

    yield return () => 2;

    dataGeneratorMetadata.TestBuilderContext.Current; // <-- A new object again
    }

    \ No newline at end of file diff --git a/docs/tutorial-extras/depends-on/index.html b/docs/tutorial-extras/depends-on/index.html index c940af301e..b892ed4ae0 100644 --- a/docs/tutorial-extras/depends-on/index.html +++ b/docs/tutorial-extras/depends-on/index.html @@ -4,7 +4,7 @@ Depends On | TUnit - + diff --git a/docs/tutorial-extras/event-subscribing/index.html b/docs/tutorial-extras/event-subscribing/index.html index 8c2177c59c..bbfa1026bd 100644 --- a/docs/tutorial-extras/event-subscribing/index.html +++ b/docs/tutorial-extras/event-subscribing/index.html @@ -4,7 +4,7 @@ Attribute Event Subscribing | TUnit - + diff --git a/docs/tutorial-extras/executors/index.html b/docs/tutorial-extras/executors/index.html index ef38c0787b..bc7ace835d 100644 --- a/docs/tutorial-extras/executors/index.html +++ b/docs/tutorial-extras/executors/index.html @@ -4,7 +4,7 @@ Executors | TUnit - + diff --git a/docs/tutorial-extras/explicit/index.html b/docs/tutorial-extras/explicit/index.html index 18b5b91929..309055056e 100644 --- a/docs/tutorial-extras/explicit/index.html +++ b/docs/tutorial-extras/explicit/index.html @@ -4,7 +4,7 @@ Explicit | TUnit - + diff --git a/docs/tutorial-extras/not-in-parallel/index.html b/docs/tutorial-extras/not-in-parallel/index.html index 0686ff63d8..449f00503c 100644 --- a/docs/tutorial-extras/not-in-parallel/index.html +++ b/docs/tutorial-extras/not-in-parallel/index.html @@ -4,7 +4,7 @@ Not in Parallel | TUnit - + diff --git a/docs/tutorial-extras/order/index.html b/docs/tutorial-extras/order/index.html index bd4147a27a..c1bb4fc0a1 100644 --- a/docs/tutorial-extras/order/index.html +++ b/docs/tutorial-extras/order/index.html @@ -4,7 +4,7 @@ Ordering Tests | TUnit - + diff --git a/docs/tutorial-extras/parallel-groups/index.html b/docs/tutorial-extras/parallel-groups/index.html index 5f8478f133..e4af6e6363 100644 --- a/docs/tutorial-extras/parallel-groups/index.html +++ b/docs/tutorial-extras/parallel-groups/index.html @@ -4,7 +4,7 @@ Parallel Groups | TUnit - + diff --git a/docs/tutorial-extras/parallel-limiter/index.html b/docs/tutorial-extras/parallel-limiter/index.html index 64760ebfcd..18a1b922bb 100644 --- a/docs/tutorial-extras/parallel-limiter/index.html +++ b/docs/tutorial-extras/parallel-limiter/index.html @@ -4,7 +4,7 @@ Parallel Limiter | TUnit - + diff --git a/docs/tutorial-extras/properties/index.html b/docs/tutorial-extras/properties/index.html index 37bbd292e1..cf4a752d7b 100644 --- a/docs/tutorial-extras/properties/index.html +++ b/docs/tutorial-extras/properties/index.html @@ -4,7 +4,7 @@ Properties | TUnit - + diff --git a/docs/tutorial-extras/property-injection/index.html b/docs/tutorial-extras/property-injection/index.html index a0237ad2f7..bec51ebce4 100644 --- a/docs/tutorial-extras/property-injection/index.html +++ b/docs/tutorial-extras/property-injection/index.html @@ -4,7 +4,7 @@ Property Injection | TUnit - + diff --git a/docs/tutorial-extras/repeating/index.html b/docs/tutorial-extras/repeating/index.html index 1554341b6d..af22440cde 100644 --- a/docs/tutorial-extras/repeating/index.html +++ b/docs/tutorial-extras/repeating/index.html @@ -4,7 +4,7 @@ Repeating | TUnit - + diff --git a/docs/tutorial-extras/retrying/index.html b/docs/tutorial-extras/retrying/index.html index d67fb237fb..4a79f749eb 100644 --- a/docs/tutorial-extras/retrying/index.html +++ b/docs/tutorial-extras/retrying/index.html @@ -4,7 +4,7 @@ Retrying | TUnit - + diff --git a/docs/tutorial-extras/setup/index.html b/docs/tutorial-extras/setup/index.html index 72e6b13654..06145cec0a 100644 --- a/docs/tutorial-extras/setup/index.html +++ b/docs/tutorial-extras/setup/index.html @@ -4,7 +4,7 @@ Test Set Ups | TUnit - + diff --git a/docs/tutorial-extras/test-context/index.html b/docs/tutorial-extras/test-context/index.html index 33ba24264b..c1e90193d9 100644 --- a/docs/tutorial-extras/test-context/index.html +++ b/docs/tutorial-extras/test-context/index.html @@ -4,7 +4,7 @@ Test Context | TUnit - + diff --git a/docs/tutorial-extras/test-filters/index.html b/docs/tutorial-extras/test-filters/index.html index 586cc33026..db3eff27ac 100644 --- a/docs/tutorial-extras/test-filters/index.html +++ b/docs/tutorial-extras/test-filters/index.html @@ -4,7 +4,7 @@ Test Filters | TUnit - + diff --git a/docs/tutorial-extras/timeouts/index.html b/docs/tutorial-extras/timeouts/index.html index 0e15e8fce3..1b5f1d1792 100644 --- a/docs/tutorial-extras/timeouts/index.html +++ b/docs/tutorial-extras/timeouts/index.html @@ -4,7 +4,7 @@ Timeouts | TUnit - + diff --git a/index.html b/index.html index dcd5f41c96..21ef79f341 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Hello from TUnit | TUnit - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 6443a41678..c9c8fb4fac 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -4,7 +4,7 @@ Markdown page example | TUnit - +