Skip to content

Commit f53f9b8

Browse files
PandaMagnusMichael Curn
and
Michael Curn
authored
Update docs (#52)
* Update for accurate information to existing functionality * Add info for AddAsyncTestBlock --------- Co-authored-by: Michael Curn <[email protected]>
1 parent 3ba57fe commit f53f9b8

File tree

1 file changed

+110
-10
lines changed

1 file changed

+110
-10
lines changed

README.md

+110-10
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,123 @@
11

2-
AspNetCore
2+
TestFramework
33
==========
44

5-
Provides test helper classes for instantiating ASP.NET Core classes like RoleManager and UserManager.
5+
IntelliTect's TestFramework helps manage test dependencies and data sharing in a highly visible and easy-to-read way. It adds a layer between your unit test method and executing code to manage the things that, in complex projects, often get abstracted away out of visibility. The goal is to provide a way to manage those dependencies without hiding them, so even people new to the project can start writing tests quickly. Under the covers, it's using dependency injection to inject test data and dependencies into test blocks only when needed. Test Framework uses a builder pattern to help facilitate highly composable tests with minimal extraneous code.
66

7-
Windows UI Test Wrapper
8-
===========
7+
Current implementation is in C#, however the pattern is language agnostic and could be implemented in other languages.
98

10-
Provides wrappers for calling Microsoft's UiTestControl classes for WPF and WinForm applications in a more concise, reliable manner
9+
Design
10+
-----
11+
TestFramework works within existing unit test frameworks and runners to help keep dependencies visible and easily reusable. You still execute your tests using NUnit, xUnit, etc. Your tests still run against a class, database connection, rest client, UI driver, etc.
1112

1213
Usage
1314
-----
14-
To use, inherit a class from the solution's DesktopControls class and make application-specific calls in the inherited class using generic types:
15+
To start, you need some executable code. Your executable code needs to live in TestBlocks. A test block is any code that derives from the TestBlock class OR implements the ITestBlock interface and has an Execute() method:
16+
```
17+
using IntelliTect.TestTools.TestFramework;
18+
19+
namespace ExampleTests.TestBlocks;
20+
21+
internal class VerifyTrueisTrue : ITestBlock
22+
{
23+
public void Execute()
24+
{
25+
Assert.True(true);
26+
}
27+
}
28+
29+
```
30+
31+
Next, in your unit test method instantiate a new TestBuilder:
32+
```
33+
[Fact]
34+
public void Test1()
35+
{
36+
TestBuilder builder = new();
37+
}
1538
```
16-
FindWpfControlByAutomationId( "textBoxControl1", c => new WpfEdit( c ) );
39+
This builder object is then used to manage everything about the test and constituent test blocks. In simple cases, you can add your test block and execute without any further setup The whole unit test looks like:
1740
```
41+
[Fact]
42+
public void Test1()
43+
{
44+
TestBuilder builder = new();
1845
19-
Inherit a class from BaseTestInherit and set the ApplicationLocation and create a new field for the above inherited class.
46+
builder.AddTestBlock<TestBlocks.VerifyTrueisTrue>()
47+
48+
TestCase test = builder.Build()
49+
test.ExecuteTestCase();
50+
}
51+
```
52+
Each test block can:
53+
- Be standalone
54+
- Have dependencies injected from external sources
55+
- Have dependencies injected from other test blocks
56+
- Create or modify dependencies for other test blocks
57+
58+
This is a simple example, and frankly would be easier as its own unit test. TestFramework shines, though, when dependencies start to become complex. While agnostic to unit, database, API, or UI testing, particularly complex API and UI testing is where we most commonly implement Test Framework. If we were to convert this to do something more interesting, we can start to see how to configure tests for different scenarios in a more interesting fashion.
59+
60+
If we take a more complex example, in this case still a relatively simple Selenium test, you can compose something like this:
61+
62+
```
63+
[Fact]
64+
public void Test1()
65+
{
66+
var expectedResult = new SiteStatus
67+
{
68+
IsHeaderAvailable = true,
69+
IsBodyAvailable = true
70+
};
71+
72+
TestBuilder builder = new();
73+
builder
74+
.AddLogger<NewLogger>()
75+
.AddDependencyService<IWebDriver>(new WebDriverFactory("Chrome").Driver)
76+
.AddDependencyService<Harness.IntelliTectWebpage>()
77+
.AddTestBlock<TestBlocks.NavigateToWebsite>()
78+
.AddTestBlock<TestBlocks.VerifyWebsiteBodyIsDisplayed>(expectedResult)
79+
.ExecuteTestCase();
80+
}
81+
```
82+
83+
This takes care of needing to have code in the test to wire up the logger, Selenium / WebDriver, and will produce errors if you (for example) add a test black that needs a dependency that isn't supplied by the test. This gives you an easy way to move complex code out of your tests and expose human-readable hooks for composing tests.
84+
85+
See the full code here: [Example Tests](https://github.com/IntelliTect/TestTools.TestFramework/tree/update-docs/ExampleTests/ExampleTests)
86+
87+
Async/Await
88+
-----
89+
TestFramework now supports test blocks that need to be awaited. Please be aware that deviating that from the standard async/await with Task or Task<T> return types can result in unexpected behavior. If you encounter these scenarios, please file an issue so we can look into it.
90+
91+
For ease of use and explicit test authoring, there is a method to tell TestFramework if a TestBlock is awaitable. Let's say you have the following test block:
92+
93+
```
94+
using IntelliTect.TestTools.TestFramework;
95+
96+
namespace ExampleTests.TestBlocks;
97+
98+
internal class VerifyAwait : ITestBlock
99+
{
100+
public async Task Execute()
101+
{
102+
await Task.Delay(1);
103+
}
104+
}
105+
```
106+
107+
To properly await this, you would build and execute your test case like so:
108+
```
109+
[Fact]
110+
public void Test1()
111+
{
112+
TestBuilder builder = new();
113+
114+
builder.AddAsyncTestBlock<TestBlocks.VerifyAwait>()
115+
116+
TestCase test = builder.Build()
117+
test.ExecuteAsync();
118+
}
119+
```
20120

21-
Inherit test classes from the BaseTestInherit inherited class, and call methods via the new field.
121+
Also note that current behavior is that TestFramework will take the result of the awaited test block task and use that for future test block dependencies. If you have a test block that returns Task<bool>, TestFramework will capture the bool result to use.
22122

23-
Example projects at https://github.com/IntelliTect/TestTools
123+
More in depth examples are coming later!

0 commit comments

Comments
 (0)