Skip to content

Commit a232e02

Browse files
committed
Update Readme.md
1 parent aed663b commit a232e02

1 file changed

Lines changed: 105 additions & 55 deletions

File tree

Readme.md

Lines changed: 105 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ You can install this library as a [NuGet package](https://www.nuget.org/packages
2121
The packages are compiled for specific versions of Revit. To support different versions of libraries in one project, use the `RevitVersion` property:
2222

2323
```xml
24-
2524
<PackageReference Include="Nice3point.TUnit.Revit" Version="$(RevitVersion).*"/>
2625
```
2726

@@ -52,28 +51,6 @@ public class MyTestClass : RevitApiTest
5251

5352
This is your runnable test. The `[TestExecutor<RevitThreadExecutor>]` attribute ensures the test executes within Revit's single-threaded API context.
5453

55-
### Global executor configuration
56-
57-
To avoid repeating the `TestExecutor` attribute for every test, you can [register](https://tunit.dev/docs/advanced/extension-points/#registering-a-test-executor) the executor globally using one of the following methods:
58-
59-
- Add the attribute to any .cs file in your project (e.g., AssemblyInfo.cs):
60-
```csharp
61-
using Nice3point.TUnit.Revit.Executors;
62-
using TUnit.Core.Executors;
63-
64-
[assembly: TestExecutor<RevitThreadExecutor>]
65-
```
66-
- Add the attribute directly to your .csproj file:
67-
```xml
68-
<!-- Global Test Executor Registration -->
69-
<ItemGroup>
70-
<AssemblyAttribute Include="TUnit.Core.Executors.TestExecutorAttribute">
71-
<_Parameter1>typeof(Nice3point.TUnit.Revit.Executors.RevitThreadExecutor)</_Parameter1>
72-
<_Parameter1_IsLiteral>true</_Parameter1_IsLiteral>
73-
</AssemblyAttribute>
74-
</ItemGroup>
75-
```
76-
7754
## Running your tests
7855

7956
**TUnit** is built on top of the **Microsoft.Testing.Platform**. Combined with source-generated tests, running your tests is available in multiple ways.
@@ -108,14 +85,14 @@ Settings > Build, Execution, Deployment > Unit Testing > Testing Platform.
10885

10986
## Application testing
11087

111-
Test Revit application-level functionality:
88+
Test Revit application-level functionality using the `Application` property exposed by `RevitApiTest`:
11289

11390
```csharp
114-
public sealed class RevitApplicationTests : RevitApiTest
91+
public sealed class ApplicationTests : RevitApiTest
11592
{
11693
[Test]
11794
[TestExecutor<RevitThreadExecutor>]
118-
public async Task Cities_Startup_IsNotEmpty()
95+
public async Task Cities_BuiltinSet_IsNotEmpty()
11996
{
12097
var cities = Application.Cities.Cast<City>();
12198

@@ -135,62 +112,135 @@ public sealed class RevitApplicationTests : RevitApiTest
135112

136113
## Document testing
137114

138-
Test document-specific operations with setup and cleanup:
115+
Tests that pass alone but fail together are a classic sign of shared state. Give each test its own document — created in `[Before(Test)]`, closed in `[After(Test)]` — and that problem disappears entirely.
116+
Use the setup hook to seed the document with exactly the state each test needs.
117+
The `[HookExecutor<RevitThreadExecutor>]` attribute ensures hooks also run on Revit's thread:
139118

140119
```csharp
141-
public sealed class RevitDocumentTests : RevitApiTest
120+
public sealed class ModelSeedTests : RevitApiTest
142121
{
143-
private static Document _documentFile = null!;
122+
private Document _document = null!;
123+
private IList<Wall> _exteriorWalls = null!;
144124

145-
[Before(Class)]
125+
[Before(Test)]
146126
[HookExecutor<RevitThreadExecutor>]
147-
public static void Setup()
127+
public void SeedModel()
148128
{
149-
_documentFile = Application.OpenDocumentFile($@"C:\Program Files\Autodesk\Revit {Application.VersionNumber}\Samples\rac_basic_sample_family.rfa");
129+
_document = Application.NewProjectDocument(UnitSystem.Metric);
130+
131+
using var transaction = new Transaction(_document, "Seed model");
132+
transaction.Start();
133+
134+
_exteriorWalls =
135+
[
136+
Wall.Create(_document, Line.CreateBound(new XYZ(0, 0, 0), new XYZ(10, 0, 0)), level.Id, false),
137+
Wall.Create(_document, Line.CreateBound(new XYZ(10, 0, 0), new XYZ(10, 6, 0)), level.Id, false),
138+
Wall.Create(_document, Line.CreateBound(new XYZ(10, 6, 0), new XYZ(0, 6, 0)), level.Id, false),
139+
Wall.Create(_document, Line.CreateBound(new XYZ(0, 6, 0), new XYZ(0, 0, 0)), level.Id, false),
140+
];
141+
142+
transaction.Commit();
150143
}
151144

152-
[After(Class)]
145+
[After(Test)]
153146
[HookExecutor<RevitThreadExecutor>]
154-
public static void Cleanup()
147+
public void CloseModel()
155148
{
156-
_documentFile.Close(false);
149+
_document.Close(false);
157150
}
158151

159152
[Test]
160153
[TestExecutor<RevitThreadExecutor>]
161-
public async Task FilteredElementCollector_ElementTypes_ValidAssignable()
154+
public async Task FilteredElementCollector_ExteriorWalls_MatchSeededCount()
162155
{
163-
var elements = new FilteredElementCollector(_documentFile)
164-
.WhereElementIsElementType()
165-
.ToElements();
166-
167-
using (Assert.Multiple())
168-
{
169-
await Assert.That(elements).IsNotEmpty();
170-
await Assert.That(elements).All().Satisfy(element => element.IsAssignableTo<ElementType>());
171-
}
156+
var walls = new FilteredElementCollector(_document)
157+
.WhereElementIsNotElementType()
158+
.OfClass(typeof(Wall))
159+
.ToList();
160+
161+
await Assert.That(walls.Count).IsEqualTo(_exteriorWalls.Count);
172162
}
173163

174164
[Test]
175165
[TestExecutor<RevitThreadExecutor>]
176-
public async Task Delete_Dimensions_ElementsWithDependenciesDeleted()
166+
public async Task Transaction_DemolishWall_RemainingWallCountDecreases()
177167
{
178-
var elementIds = new FilteredElementCollector(_documentFile)
179-
.WhereElementIsNotElementType()
180-
.OfCategory(BuiltInCategory.OST_Dimensions)
181-
.OfClass(typeof(RadialDimension))
182-
.ToElementIds();
168+
var targetId = _exteriorWalls[0].Id;
183169

184-
using var transaction = new Transaction(_documentFile);
185-
transaction.Start("Delete dimensions");
186-
var deletedElements = _documentFile.Delete(elementIds);
170+
using var transaction = new Transaction(_document, "Demolish wall");
171+
transaction.Start();
172+
_document.Delete(targetId);
187173
transaction.Commit();
188174

189-
await Assert.That(deletedElements.Count).IsGreaterThanOrEqualTo(elementIds.Count);
175+
var remainingWalls = new FilteredElementCollector(_document)
176+
.WhereElementIsNotElementType()
177+
.OfClass(typeof(Wall))
178+
.ToElementIds();
179+
180+
await Assert.That(remainingWalls.Count).IsEqualTo(_exteriorWalls.Count - 1);
190181
}
191182
}
192183
```
193184

194185
> [!NOTE]
195186
> The examples demonstrate basic testing functionality. This library **only adds support for working within the Revit API context**. For comprehensive documentation on assertions, attributes, test configuration, and
196187
> advanced features, please refer to the official [TUnit documentation](https://thomhurst.github.io/TUnit/).
188+
189+
More examples, including parametrized model and family tests, are available in the [test project](https://github.com/Nice3point/RevitUnit/tree/main/Nice3point.TUnit.Revit.Tests).
190+
191+
## Test configuration
192+
193+
### Global executor
194+
195+
To avoid repeating the `TestExecutor` attribute for every test, you can [register](https://tunit.dev/docs/advanced/extension-points/#registering-a-test-executor) the executor globally using one of the following methods:
196+
197+
- Add the attribute to any .cs file in your project (e.g., TestsConfiguration.cs):
198+
199+
```csharp
200+
using Nice3point.TUnit.Revit.Executors;
201+
using TUnit.Core.Executors;
202+
203+
[assembly: TestExecutor<RevitThreadExecutor>]
204+
```
205+
206+
- Add the attribute directly to your .csproj file:
207+
208+
```xml
209+
<!-- Global Test Executor Registration -->
210+
<ItemGroup>
211+
<AssemblyAttribute Include="TUnit.Core.Executors.TestExecutorAttribute">
212+
<_Parameter1>typeof(Nice3point.TUnit.Revit.Executors.RevitThreadExecutor)</_Parameter1>
213+
<_Parameter1_IsLiteral>true</_Parameter1_IsLiteral>
214+
</AssemblyAttribute>
215+
</ItemGroup>
216+
```
217+
218+
### Revit Environment
219+
220+
TUnit initializes Revit with the `English - United States` language and the `C:\Program Files\Autodesk\Revit {version}` installation path. To override these defaults, use assembly-level attributes:
221+
222+
- Add the attributes to any .cs file in your project (e.g., TestsConfiguration.cs):
223+
224+
```csharp
225+
using Nice3point.Revit.Injector.Attributes;
226+
227+
[assembly: RevitLanguage("ENG")]
228+
[assembly: RevitInstallationPath("D:\Autodesk\Revit Preview")]
229+
```
230+
231+
- Add the attributes directly to your .csproj file:
232+
233+
```xml
234+
<!-- Revit Environment Configuration -->
235+
<ItemGroup>
236+
<AssemblyAttribute Include="Nice3point.Revit.Injector.Attributes.RevitLanguageAttribute">
237+
<_Parameter1>ENG</_Parameter1>
238+
</AssemblyAttribute>
239+
<AssemblyAttribute Include="Nice3point.Revit.Injector.Attributes.RevitInstallationPathAttribute">
240+
<_Parameter1>D:\Autodesk\Revit $(RevitVersion)</_Parameter1>
241+
</AssemblyAttribute>
242+
</ItemGroup>
243+
```
244+
245+
The `RevitLanguage` attribute accepts a [language](https://help.autodesk.com/view/RVT/2026/ENU/?guid=GUID-BD09C1B4-5520-475D-BE7E-773642EEBD6C) name (e.g., "English - United States"), code (e.g., "ENU")
246+
or [LanguageType](https://www.revitapidocs.com/2026/dfda33cf-cbff-9fde-6672-38402e87510f.htm) enum value (e.g., "English_GB" or "15").

0 commit comments

Comments
 (0)