Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Raise event when stubbed property is changed #745

Closed
yordans opened this issue Jan 30, 2019 · 10 comments
Closed

Raise event when stubbed property is changed #745

yordans opened this issue Jan 30, 2019 · 10 comments

Comments

@yordans
Copy link

yordans commented Jan 30, 2019

How to raise event when stubbed property (automatically tracking its value) is changed (setter called)?

e.g.
mock.SetupProperty(m => m.Foo).Raises(m => m.FooChanged += null);
mock.Object.Foo = 5; // raises the FooChanged event on ISomething

@yordans
Copy link
Author

yordans commented Jan 31, 2019

I want the event to be fired automatically when a stubbed property is changed but it seems that this functionality is missing.

@stakx
Copy link
Contributor

stakx commented Feb 5, 2019

@yordans - It appears that you've already answered your own question for the most part:

public interface IFoo
{
    int Foo { get; set; }
    event EventHandler FooChanged;
}

var mock = new Mock<IFoo>();
mock.Object.FooChanged += (s, e) => Console.WriteLine("Foo property changed.");
mock.SetupSet(m => m.Foo = It.IsAny<int>()).Raises(m => m.FooChanged += null, EventArgs.Empty);
mock.Object.Foo = 5;

The above will fire the event whenever the property is set, not when it is changed. If you want the latter, you'll need something more elaborate:

int value = default(int);  // this will act as the "backing field" for the property
mock.SetupGet(m => m.Foo).Returns(() => value);
mock.SetupSet(m => m.Foo = It.IsAny<int>()).Callback((int newValue) =>
{
    bool shouldRaiseChangedEvent = newValue != value;
    value = newValue;
    if (shouldRaiseChangedEvent)
    {
        mock.Raise(m => m.FooChanged += null, EventArgs.Empty);
    }
});

Not so different from how you'd implement INotifyPropertyChanged. (SetupProperty is actually implemented in a very similar way to the above, it just lacks the logic to determine value changes and trigger an event.)

If you want an API that creates such a setup for any pair of a property P and an event PChanged, it should be easy to create it as an extension method. Because neither the member names nor the property type will be known in advance, you'll have to build the expressions for Setup and Raise yourself (using the static Expression factory methods) instead of letting the compiler do it for you.

Does this answer your question?

@yordans
Copy link
Author

yordans commented Feb 5, 2019

It is fine the event to be fired when the property is set, but the real problem is that I want the mock to "track" sets/gets to this property (i.e. Stub) + firing event.

mock.SetupSet(m => m.Foo = It.IsAny<int>())

won't track the property Foo.

@stakx
Copy link
Contributor

stakx commented Feb 5, 2019

What exactly do you mean by "tracking a property"?

sets/gets to this property (i.e. Stub) + firing event

Did you notice the second part of my above post? Because that's exactly what it does.

@yordans
Copy link
Author

yordans commented Feb 6, 2019

When setup property in this way:
mock.SetupProperty(m => m.Foo);
it is a Stub and it tracks its changes, so if latter call mock.Object.Foo = 5 and then get the value, it will be 5.

And the question is could this kind of stubbed property be setup to raise an event when changed?

@stakx
Copy link
Contributor

stakx commented Feb 6, 2019

And the question is could this kind of stubbed property be setup to raise an event when changed?

I'll once again refer you to my first post above which shows you just how to do that. (And no, SetupProperty currently doesn't offer a way to do this out of the box.)

@yordans
Copy link
Author

yordans commented Feb 6, 2019

Thank you for your responses. I think the issue can be closed.

Is it planned SetupProperty to offer a way for raising events out of the box?

@stakx
Copy link
Contributor

stakx commented Feb 6, 2019

Is it planned SetupProperty to offer a way for raising events out of the box?

No, such an extension isn't planned at the moment.

@stakx stakx closed this as completed Feb 6, 2019
@jhv2017kam
Copy link

@stakx When implementing what you describe here I ran in to the problem that property.ToPropertyInfo(); used in the newest version of SetupProperty is placed in an internal extensions class would it be possible to have ToProperty be part of the public API?

@stakx
Copy link
Contributor

stakx commented Sep 17, 2021

@jhv2017kam, no, that helper method definitely does not belong in Moq's public API... it's strictly an implementation detail. But it should be easy enough to replicate in your own code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants