Skip to content

Commit 372061d

Browse files
committed
Adapt README.md
1 parent 9d22d60 commit 372061d

2 files changed

Lines changed: 42 additions & 181 deletions

File tree

Docs/pages/src/pages/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function HomepageCodeSample() {
103103
<p className={clsx('text--center', styles.codeSampleSubtitle)}>
104104
Depend on <code>IFileSystem</code>, <code>ITimeSystem</code> and{' '}
105105
<code>IRandomSystem</code> in production. Swap in the in-memory mocks for
106-
tests deterministic, cross-platform, no temp folders or{' '}
106+
tests - deterministic, cross-platform, no temp folders or{' '}
107107
<code>Thread.Sleep</code>.
108108
</p>
109109
<div className={styles.codeSampleContainer}>

README.md

Lines changed: 41 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -1,203 +1,64 @@
1-
![Testably.Abstractions](https://raw.githubusercontent.com/Testably/Testably.Abstractions/main/Docs/Images/social-preview.png)
2-
[![Nuget](https://img.shields.io/nuget/v/Testably.Abstractions?label=Testably.Abstractions)](https://www.nuget.org/packages/Testably.Abstractions)
3-
[![Nuget](https://img.shields.io/nuget/v/Testably.Abstractions.Testing?label=Testing)](https://www.nuget.org/packages/Testably.Abstractions.Testing)
4-
[![Build](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml/badge.svg)](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml)
5-
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
6-
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=coverage)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
7-
8-
This library is a feature complete testing helper for the [IFileSystem abstractions for I/O-related functionality](https://github.com/TestableIO/System.IO.Abstractions) from the `System.IO` namespace. It uses an in-memory file system that behaves exactly like the real file system and can be used in unit tests for dependency injection.
9-
The testing helper also supports advanced scenarios like
10-
- [Multiple drives with limited size](Examples/DriveManagement/README.md)
11-
- [`FileSystemWatcher`](Examples/FileSystemWatcher/README.md) and
12-
- a way to work with [SafeFileHandles](Examples/SafeFileHandle/README.md)
13-
14-
The companion projects [Testably.Abstractions.Compression](https://www.nuget.org/packages/Testably.Abstractions.Compression) and [Testably.Abstractions.AccessControl](https://www.nuget.org/packages/Testably.Abstractions.AccessControl) allow working with [Zip-Files](Examples/ZipFile/README.md) and [Access Control Lists](Examples/AccessControlLists/README.md) respectively.
15-
16-
As the test suite runs both against the mocked and the real file system, the behaviour between the two is identical and it also allows [simulating the file system on other operating systems](#simulating-other-operating-systems) (Linux, MacOS and Windows).
17-
18-
In addition, the following interfaces are defined:
19-
- The `ITimeSystem` interface abstracts away time-related functionality:
20-
- `DateTime` methods give access to the current time
21-
- `Stopwatch` is a wrapper around [`System.Diagnostics.Stopwatch`](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch)
22-
- `Task` allows replacing [`Task.Delay`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay)
23-
- `Thread` allows replacing [`Thread.Sleep`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.sleep)
24-
- `PeriodicTimer` is a wrapper around [`System.Threading.PeriodicTimer`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.periodictimer)
25-
- `Timer` is a wrapper around [`System.Threading.Timer`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.timer)
26-
- The `IRandomSystem` interface abstracts away functionality related to randomness:
27-
`Random` methods implement a thread-safe Shared instance also under .NET Framework and `Guid` methods allow creating new GUIDs.
28-
29-
## Example
30-
Use the interfaces and their default implementations using your prefered dependency injection method, e.g.:
31-
```csharp
32-
private readonly IFileSystem _fileSystem;
1+
# Testably.Abstractions
332

34-
public class MyService(IFileSystem fileSystem)
35-
{
36-
_fileSystem = fileSystem;
37-
}
3+
[![Testably.Abstractions](https://img.shields.io/nuget/v/Testably.Abstractions?label=Testably.Abstractions&logo=nuget)](https://www.nuget.org/packages/Testably.Abstractions)
4+
[![Testably.Abstractions.Testing](https://img.shields.io/nuget/v/Testably.Abstractions.Testing?label=Testing&logo=nuget)](https://www.nuget.org/packages/Testably.Abstractions.Testing)
5+
[![Build](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml/badge.svg)](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml)
6+
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
7+
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=coverage)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
388

39-
public void StoreData()
40-
{
41-
var fileContent = GetFileContent();
42-
_fileSystem.File.WriteAllText("result.xml", fileContent);
43-
}
9+
Injectable abstractions for the static parts of the .NET BCL - file system, time and randomness - with feature-complete in-memory mocks for tests.
10+
11+
**📖 Full documentation: [docs.testably.org](https://docs.testably.org)**
12+
13+
## Quick example
4414

45-
private string GetFileContent()
15+
```csharp
16+
public class ReportService(IFileSystem fileSystem)
4617
{
47-
// Generate the file content
18+
public void Save(string content)
19+
{
20+
fileSystem.Directory.CreateDirectory("reports");
21+
fileSystem.File.WriteAllText("reports/latest.xml", content);
22+
}
4823
}
4924
```
5025

51-
Then you test your class with the mocked types in `Testably.Abstractions.Testing`:
5226
```csharp
53-
[Test]
54-
public void StoreData_ShouldWriteValidFile()
27+
[Fact]
28+
public async Task Save_WritesReportToReportsFolder()
5529
{
56-
IFileSystem fileSystem = new MockFileSystem();
57-
MyService sut = new MyService(fileSystem);
30+
var fileSystem = new MockFileSystem();
31+
var sut = new ReportService(fileSystem);
5832

59-
sut.StoreData();
33+
sut.Save("<report />");
6034

61-
var fileContent = fileSystem.File.ReadAllText("result.xml");
62-
// Validate fileContent
35+
await Expect.That(fileSystem.File.ReadAllText("reports/latest.xml"))
36+
.IsEqualTo("<report />");
6337
}
6438
```
6539

66-
**More examples can be found in the [examples section](Examples/README.md)!**
67-
68-
## Getting Started
69-
70-
- Install `Testably.Abstractions` as nuget package in your production projects and `Testably.Abstractions.Testing` as nuget package in your test projects.
71-
```ps
72-
dotnet add package Testably.Abstractions
73-
dotnet add package Testably.Abstractions.Testing
74-
```
75-
76-
- Configure your dependeny injection framework, e.g. with `Microsoft.Extensions.DependencyInjections` in ASP.NET core:
77-
```csharp
78-
builder.Services
79-
.AddSingleton<IFileSystem, RealFileSystem>()
80-
.AddSingleton<IRandomSystem, RealRandomSystem>()
81-
.AddSingleton<ITimeSystem, RealTimeSystem>();
82-
```
83-
84-
**You can now use the interfaces in your services!**
85-
86-
## Testing
87-
In order to simplify testing, the `Testably.Abstractions.Testing` project provides mocked instances for the abstraction interfaces, which are configured using fluent syntax:
40+
## Install
8841

89-
### Initialization
90-
91-
The following two code snippets initialize the mocked `fileSystem` with a structure like the following:
92-
- Directory "foo"
93-
- Directory "bar"
94-
- Empty file "bar.txt"
95-
- File "foo.txt" with "some file content" as content
96-
97-
```csharp
98-
var fileSystem = new MockFileSystem();
99-
fileSystem.Initialize().With(
100-
new DirectoryDescription("foo",
101-
new DirectoryDescription("bar"),
102-
new FileDescription("bar.txt")),
103-
new FileDescription("foo.txt", "some file content"));
42+
```ps
43+
dotnet add package Testably.Abstractions
44+
dotnet add package Testably.Abstractions.Testing
10445
```
10546

106-
```csharp
107-
var fileSystem = new MockFileSystem();
108-
fileSystem.Initialize()
109-
.WithSubdirectory("foo").Initialized(d => d
110-
.WithSubdirectory("bar")
111-
.WithFile("bar.txt"))
112-
.WithFile("foo.txt").Which(f => f.HasStringContent("some file content"));
113-
```
47+
Then register the implementations in your DI container - see [Getting Started](https://docs.testably.org/docs/getting-started).
11448

115-
### Simulating other operating systems
49+
## Packages
11650

117-
The `MockFileSystem` can also simulate other operating systems than the one it is currently running on. This can be achieved, by providing the corresponding `SimulationMode` in the constructor:
51+
| Package | Purpose |
52+
|--------------------------------------|-------------------------------------------------------------------------|
53+
| `Testably.Abstractions` | Production interfaces (`IFileSystem`, `ITimeSystem`, `IRandomSystem`) |
54+
| `Testably.Abstractions.Testing` | `MockFileSystem`, `MockTimeSystem`, `MockRandomSystem` |
55+
| `Testably.Abstractions.Compression` | Zip / `ZipArchive` extension methods on `IFileSystem` |
56+
| `Testably.Abstractions.AccessControl`| `GetAccessControl` / `SetAccessControl` on files and directories |
11857

119-
```csharp
120-
var linuxFileSystem = new MockFileSystem(o => o.SimulatingOperatingSystem(SimulationMode.Linux));
121-
// The `linuxFileSystem` now behaves like a Linux file system even under Windows:
122-
// - case-sensitive
123-
// - slash as directory separator
124-
125-
var windowsFileSystem = new MockFileSystem(o => o.SimulatingOperatingSystem(SimulationMode.Windows));
126-
// The `windowsFileSystem` now behaves like a Windows file system even under Linux or MacOS:
127-
// - multiple drives
128-
// - case-insensitive
129-
// - backslash as directory separator
130-
```
58+
## Already on TestableIO?
13159

132-
By running all tests against the real file system and the simulated under Linux, MacOS and Windows, the behaviour is consistent between the native and simulated mock file systems.
60+
`Testably.Abstractions` shares the `IFileSystem` interface with [TestableIO.System.IO.Abstractions](https://github.com/TestableIO/System.IO.Abstractions), so production code stays untouched. See the [migration guide](https://docs.testably.org/docs/migration-from-testableio).
13361

134-
### Drive management
135-
```csharp
136-
var fileSystem = new MockFileSystem();
137-
fileSystem
138-
.WithDrive("D:", d => d
139-
.SetTotalSize(1024 * 1024))
140-
.InitializeIn("D:")
141-
.WithFile("foo.txt")
142-
.WithSubdirectory("sub-dir").Initialized(s => s
143-
.WithAFile(".json").Which(
144-
f => f.HasStringContent("{\"count\":1}")));
145-
```
146-
Initializes the mocked file system with a second drive `D:` with 1MB total available space and creates on it an empty text file `foo.txt` and a directory `sub-dir` which contains randomly named json file with `{"count":1}` as file content.
147-
148-
On non-Windows systems, the main drive can still be configured, e.g.
149-
```csharp
150-
var fileSystem = new MockFileSystem();
151-
fileSystem.WithDrive(d => d.SetTotalSize(20));
152-
153-
// this will throw an IOException that there is not enough space on the disk.
154-
fileSystem.File.WriteAllText("foo", "some text longer than 20 bytes");
155-
```
62+
## Contributing
15663

157-
## Relationship with TestableIO.System.IO.Abstractions
158-
159-
This library uses the same interfaces as [TestableIO.System.IO.Abstractions](https://github.com/TestableIO/System.IO.Abstractions), which means you can switch between the two testing libraries **without changing your production code**. Both libraries provide `IFileSystem` implementations, but with different testing capabilities and API surfaces.
160-
161-
### When to use Testably.Abstractions vs TestableIO
162-
- **Use Testably.Abstractions** if you need:
163-
- Advanced testing scenarios (FileSystemWatcher, SafeFileHandles, multiple drives)
164-
- Additional abstractions (ITimeSystem, IRandomSystem)
165-
- Cross-platform file system simulation (Linux, MacOS, Windows)
166-
- More extensive and consistent behavior validation
167-
- Active development and new features
168-
169-
- **Use TestableIO.System.IO.Abstractions** if you need:
170-
- Basic file system mocking capabilities
171-
- Direct manipulation of stored file entities (MockFileData, MockDirectoryData)
172-
- Established codebase with existing TestableIO integration
173-
174-
### Migrating from TestableIO
175-
Switching from TestableIO to Testably only requires changes in your test projects:
176-
177-
1. Replace the NuGet package reference in your test projects:
178-
```xml
179-
<!-- Remove -->
180-
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" />
181-
<!-- Add -->
182-
<PackageReference Include="Testably.Abstractions.Testing" />
183-
```
184-
185-
2. Update your test code to use the new `MockFileSystem`:
186-
```csharp
187-
// Before (TestableIO)
188-
var fileSystem = new MockFileSystem();
189-
fileSystem.AddDirectory("some-directory");
190-
fileSystem.AddFile("some-file.txt", new MockFileData("content"));
191-
192-
// After (Testably)
193-
var fileSystem = new MockFileSystem();
194-
fileSystem.Directory.CreateDirectory("some-directory");
195-
fileSystem.File.WriteAllText("some-file.txt", "content");
196-
// or using fluent initialization:
197-
fileSystem.Initialize()
198-
.WithSubdirectory("some-directory")
199-
.WithFile("some-file.txt").Which(f => f
200-
.HasStringContent("content"));
201-
```
202-
203-
Your production code using `IFileSystem` remains unchanged.
64+
Issues and pull requests are welcome - see [CONTRIBUTING.md](CONTRIBUTING.md) and the [issue tracker](https://github.com/Testably/Testably.Abstractions/issues).

0 commit comments

Comments
 (0)