Skip to content

Observing changes in the MockFileSystem #805

Description

@SuperJMN

Describe the solution you'd like
I'd like to be able to observe common/interesting events (from a testing perspective) that happen into a MockFileSystem.

Why? I'm creating a cache service that uses an IFileSystem and I need to test that a file is only written once.

Describe alternatives you've considered
I've tried to implement my own MockFileSystem using System.Reactive, but the work is a bit overwhelming.

Activity

  1. fgreinacher commented on Feb 16, 2022

    @fgreinacher
    Contributor

    This is the same as #168 which has gone stale.

    As mentioned over there I generally like the idea and would accept a contribution here unless it's getting overly complex.

  2. added
    state: ready to pickIssues that are ready for being worked on
    and removed on Feb 16, 2022
  3. mistial-dev commented on Jul 13, 2025

    @mistial-dev

    This is the same as #168 which has gone stale.

    As mentioned over there I generally like the idea and would accept a contribution here unless it's getting overly complex.

    What do you think of an approach like this?

    #1313

  4. mistial-dev commented on Jul 13, 2025

    @mistial-dev

    The neat thing about this kind of approach is that it makes testing certain scenarios easier. For example:

      var fileSystem = new MockFileSystem(new MockFileSystemOptions { EnableEvents = true });
    
      // Make everything read-only with one subscription
      using (fileSystem.Events.Subscribe(args =>
      {
          if (args.Phase == OperationPhase.Before &&
              (args.Operation == FileOperation.Write ||
               args.Operation == FileOperation.Delete ||
               args.Operation == FileOperation.Create))
          {
              args.SetResponse(new OperationResponse
              {
                  Exception = new UnauthorizedAccessException("File system is read-only")
              });
          }
      }))
      {
          // This will throw UnauthorizedAccessException
          fileSystem.File.WriteAllText(@"C:\test.txt", "data");
      }

    Or generic logging, etc.

      var fs = new MockFileSystem(new MockFileSystemOptions { EnableEvents = true });
      var log = new List<string>();
    
      using (fs.Events.Subscribe(args =>
      {
          if (args.Phase == OperationPhase.After)
              log.Add($"{args.Operation} on {args.Path}");
      }))
      {
          // Your test code here
          MyService.ProcessFiles(fs);
    
          // Now you can assert on what actually happened
          Assert.That(log, Contains.Item("Delete on C:\\temp\\cache.tmp"));
      }
      // Simulate disk full on the third write
      var writeCount = 0;
      using (fs.Events.Subscribe(FileOperation.Write, args =>
      {
          if (++writeCount >= 3 && args.Phase == OperationPhase.Before)
          {
              args.SetResponse(new OperationResponse
              {
                  Exception = new IOException("Disk full")
              });
          }
      }))
      {
          // Test your retry logic, error handling, etc.
      }
      // Prevent deletion of important files
      using (fs.Events.Subscribe(FileOperation.Delete, args =>
      {
          if (args.Phase == OperationPhase.Before && args.Path.EndsWith(".config"))
          {
              args.SetResponse(new OperationResponse
              {
                  Exception = new UnauthorizedAccessException("Config files are protected")
              });
          }
      }))
      {
          // Deletion is prevented
      }
  5. mistial-dev commented on Jul 13, 2025

    @mistial-dev

    The actual syntax to add events is pretty minimal. For example:

            return mockFileDataAccessor.Events.WithEvents(fullPath, FileOperation.Read, ResourceType.File, () =>
            {
                // ... existing code
                return ReadAllTextInternal(path, encoding);
            });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: testinghelpersIssues that address the testing helpersstate: ready to pickIssues that are ready for being worked ontype: enhancementIssues that propose new functionality

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions