Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Provide a way to pass null for custom event args so that Raise.EventWith can be used to raise events for custom event args without a default constructor #788

Open
zhitchcock77 opened this issue Mar 27, 2024 · 0 comments
Labels
feature-request Request for a new NSubstitute feature

Comments

@zhitchcock77
Copy link

Is your feature request related to a problem? Please describe.
Currently if we want to test raising an event that has custom events args (rather than just using EventArgs), the custom event args class must have a default constructor or some method to create the object. This is because NSubstitute will attempt to create an instance of the event args if we provide null (see code here) when calling Raise.EventWith.

However, it is not necessary for a class to have a public constructor (e.g. constructor could be internal), and therefore if the custom event args class doesn't have a publicly accessible constructor, there is no way to raise the event using Raise.EventWith

Describe the solution you'd like
It would be great if there was a way that Raise.EventWith could be called where null can be provided for the custom event arg, and NSubstitue does not attempt to create an instance of the custom event arg.

One possible solution is to not throw the exception if the call to GetDefaultConstructor returns null, and in that case, just return null from the GetDefaultForEventArgType method.

Additional context
Below is some example code demonstrating this problem:

namespace NSubstituteEventArgs
{
    public class CustomEventArgs : EventArgs
    {
        internal CustomEventArgs() { }
    }

    public interface IExample
    {
        public event EventHandler<CustomEventArgs> MyEvent;

        public void DoSomethingToTriggerMyEvent();

    }
    
    internal class Example : IExample
    {
        public event EventHandler<CustomEventArgs>? MyEvent;

        public void DoSomethingToTriggerMyEvent()
        {
            Console.WriteLine("DoSomethingToTriggerMyEvent called in Example");
            OnMyEvent(new CustomEventArgs());
        }

        private void OnMyEvent(CustomEventArgs e)
        {
            MyEvent?.Invoke(this, e);
        }
    }

    public class Consumer
    {
        private readonly IExample _example;

        public Consumer(IExample example)
        {
            _example = example;
            _example.MyEvent += _example_MyEvent;
        }

        private void _example_MyEvent(object? sender, CustomEventArgs e)
        {
            DoSomething();
            Console.WriteLine("MyEvent handled by Consumer");
        }

        public void DoSomething()
        {
            Console.WriteLine("DoSomething method called in Consumer");
        }
    }
}

And the unit test below will fail with the message: NSubstitute.Exceptions.CannotCreateEventArgsException : Cannot create CustomEventArgs for this event as it has no default constructor. Provide arguments for this event by calling Raise.EventWith(CustomEventArgs).

  [Fact]
  public void DoSomething_WhenMyEventIsRaised_IsCalled()
  {
      // Arrange
      IExample mockExample = Substitute.For<IExample>();
      var consumer = new Consumer(mockExample);

      // Act
      mockExample.MyEvent += Raise.EventWith<CustomEventArgs>(this, (CustomEventArgs)null!);

      // Assert
      consumer.Received(1).DoSomething();
  }
@zhitchcock77 zhitchcock77 changed the title Provide a way to pass null for custom event args so that Raise.EventWith can be used to call event handlers Provide a way to pass null for custom event args so that Raise.EventWith can be used to raise events for custom event args without a default constructor Mar 27, 2024
@304NotModified 304NotModified added the feature-request Request for a new NSubstitute feature label Apr 29, 2024
dtchepak added a commit that referenced this issue Jun 2, 2024
…ntWith-default-constructor

Raise.EventWith default constructor (#788)
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
feature-request Request for a new NSubstitute feature
Projects
None yet
Development

No branches or pull requests

2 participants