I have an event and a raising method as below :
public class Events {
public event EventHandler<CustomEventArgs> Succeed;
public virtual void OnSucceed(object sender, params object[] data)
{
CustomEventArgs args = new CustomEventArgs(data);
EventHandler<CustomEventArgs> _succeed = Succeed;
if (_succeed != null)
{
_succeed(sender, args);
}
}}
I have created a unit test for the OnSucceed method (using FluentAssertions ):
[Test]
public void SucceedShouldNotBeRaisedTest()
{
Events events = new Events();
events.MonitorEvents();
events.OnSucceed(this,"somedata");
events.ShouldNotRaise("Succeed");
}
as there is no subscriber to the event then I expect it not to raise Succeed event
but the test fails as Succeed event is raised . what's wrong with this ?!
When you call events.MonitorEvents();, FluentAssertions automatically subscribe to the public events to detect when an event has been raised.
Your test is failing because your condition will always evaluate to true: if (_succeed != null). When testing, the event will always be different from null
Now I would like to recommend you to following approach proposed by Jon Skeet:
public event EventHandler<CustomEventArgs> Succeed = delegate { } ;
With the above event declaration, your event will never be null (an event cannot be assigned from outside of its class)
Note: You can assign the delegate behind the event to null inside its class like this:
this.Succeed = null;
The above statement is assigning the delegate behind the event to null, not the event itself. Usually you won't need to do something like this, but in case you do, you would have to re-initialize the event like this:
this.Succeed = null;
this.Succeed = delegate { };
If you follow these suggestions, your event will never be null and you won't need to call the if(this.MyEvent != null) condition in order to raise your events anymore. (Note that this condition was totally technical and it's not related to the domain itself.)
Now that you have removed that technical condition you can actually focus in the domain rules to decide when to raise the event.
The last step would be to remove: if (_succeed != null) and add a condition indicating if the event should or should not be raised based on your current domain
if(shouldRaiseEvent)
{
EventHandler<CustomEventArgs> _succeed = Succeed;
_succeed(...);
}
For your tests, you just need to configure your Subject Under Test with the required conditions in order to raise or not raise your events.
Full sample:
public class Events {
public event EventHandler<CustomEventArgs> Succeed = delegate { };
public virtual void OnSucceed(object sender, params object[] data)
{
if (/*[optional] here your domain condition that will indicate if the event should be raised*/)
{
// this is a best practice to deal with multi-threading situations
var _succeed = this.Succeed;
var args = new CustomEventArgs(data);
_succeed(sender, args);
}
}
}
Related
I've created a custom activity which contains as a Body another Activity.
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
}
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
throw new Exception(propagatedException.Message);
}
When an exception is thrown during the execution of the Body, ma handler for the OnFaulted is hit.
My execution starts with a call to static method Run of the WorkflowApplication class. My WorkflowApplication instance has a handler associated for the OnUnhandledException event.
instance.OnUnhandledException +=
delegate(WorkflowApplicationUnhandledExceptionEventArgs args)
{
Console.WriteLine(args.ExceptionSource);
waitEvent.Set();
return UnhandledExceptionAction.Cancel;
};
But regardless of what happens when the Activity hosted in the Body is executed, i never reach the handler defined above. I thought that if i throw an exception from the OnFaulted, i will be able to redirect the flow to the OnUnhandledException but i was wrong. Any ideas ?
I need this in order to centralize my errors, check them and display messages accordingly. Also i need a way to stop the execution and so on and i don't want to define handlers all over the application. Is there any way to accomplish this ?
As Will suggested, i will post what i did to handle my scenario.
Basically, in my custom activity i have hosted an Assign :
[Browsable(false)]
public Activity Body { get; set; }
Activity System.Activities.Presentation.IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new Assignment()
{
Body = new Assign() { DisplayName = "" }
};
}
I've added this code to my Execute method :
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
I was trying to run this Assignment by giving an array a negative value as index and and an exception was thrown. This, somehow ended my execution but no handler for the events of my WorkflowApplication instance were hit.
Here is the method given as a callback when executing the body ( in our case the Assign activity ) :
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
faultContext.HandleFault();
CommunicationExtension ce = faultContext.GetExtension<CommunicationExtension>();
ITextExpression toTextExpression = (propagatedFrom.Activity as Assign).To.Expression as ITextExpression;
string valueTextExpression = string.Empty;
if ((propagatedFrom.Activity as Assign).Value != null)
{
if ((propagatedFrom.Activity as Assign).Value.Expression != null)
valueTextExpression = (propagatedFrom.Activity as Assign).Value.Expression.ToString();
}
if (ce != null)
{
ce.AddData(string.Format("{0} found on Assignment definition [{1} = {2}]", propagatedException.Message, toTextExpression.ExpressionText, valueTextExpression));
}
}
The trick was to call :
faultContext.HandleFault();
and use CommunicationExtension to allow me to to display the erros in the GUI.
The code for this class is trivial :
public class CommunicationExtension
{
public List<string> Messages { get; set; }
public CommunicationExtension()
{
Messages = new List<string>();
}
public void AddData(string message)
{
if (string.IsNullOrEmpty(message))
return;
Messages.Add(message);
}
}
Use this to add the extension:
CommunicationExtension ce = new CommunicationExtension();
instance.Extensions.Add(ce);
where instance is my WorkflowApplication instance.
I understood that for each instance of the workflow application we have one instance of its extension class. So i can send messages like this from all my custom activities in order to display their status.
I hope this scenario can help other people too.
I have created a TcmExtension named WorkflowEventSystem that has an event handler subscribed to the FinishProcess event. The purpose of this event is to schedule for publish all dependencies (i.e. pages) of the associated workflow subject.
The problem I am having is that even though the event triggers at the right time (a workflow process is completed), and all the items that are supposed to be scheduled for publish are, the PublishScheduler object created by the event never seems to go out of scope, and as such the WorkflowEventSystem object does not either.
Is there something I am missing about how the Event System works that would cause these objects to live on forever? I've included what I consider the relevant code below (some parts summarized). Thanks for any help.
Here's most of the actual TcmExtension:
public class WorkflowEventSystem : TcmExtension
{
public WorkflowEventSystem()
{
this.Subscribe();
}
public void Subscribe()
{
EventSystem.Subscribe<ProcessInstance, FinishProcessEventArgs>(ScheduleForPublish, EventPhases.All);
}
}
ScheduleForPublish creates a PublishScheduler object (class I created):
private void ScheduleForPublish(ProcessInstance process, FinishProcessEventArgs e, EventPhases phase)
{
if(phase == EventPhases.TransactionCommitted)
{
PublishScheduler publishScheduler = new PublishScheduler(process);
publishScheduler.ScheduleForPublish(process);
publishScheduler = null; // worth a try
}
}
The ScheduleForPublish method looks similar to this:
public void ScheduleForPublish(ProcessInstance process)
{
using(Session session = new Session("ImpersonationUser"))
{
var publishInstruction = new PublishInstruction(session);
// Set up some publish Instructions
var publicationTargets = new List<PublicationTarget>();
// Add a PublicationTarget here by tcm id
IList<VersionedItem> itemsToPublish = new List<VersionedItem>();
// Add the items we want to publish by calling GetUsingItems(filter)
// on the workflow process' subject
//Publish the items
PublishEngine.Publish(itemsToPublish.Cast<IdentifiableObject>(), publishInstruction, publishTargets);
}
}
Life-cycle management for TcmExtension classes is quite simple:
when you call Subscribe the TcmExtension object you specify is added to an internal list of subscriptions
when you later call Unsubscribe the same TcmExtension object is removed from the list of subscriptions
Since you never call Unsubscribe your WorkflowEventSystem is never removed and thus will never be garbage collected by .NET. And since your WorkflowEventSystem holds a reference to the PublishScheduler instance it created, that one will thus also never be cleaned up.
The proper boilerplate for a custom TcmExtension is:
public class WorkflowEventSystem : TcmExtension, IDisposable
{
EventSubscription _subscription;
public WorkflowEventSystem()
{
this.Subscribe();
}
public void Subscribe()
{
_subscription = EventSystem.Subscribe<ProcessInstance,
FinishProcessEventArgs>(ScheduleForPublish, EventPhases.All);
}
public void Dispose()
{
_subscription.Unsubscribe();
}
}
Nuno also gave a longer example (handling multiple subscribers) in this article:
http://nunolinhares.blogspot.nl/2012/07/validating-content-on-save-part-1-of.html
I've 2 user controls named UCCreateProfile.ascx (used for creating/editing profile data) and UCProfileList.ascx (used to display profile data in GridView). Now whenever a new profile created I want to update my UCProfileList control to show new entry.
The best solution against above problem I've to go for Observer Pattern. In my case UCCreatedProfile is a Subject/Observable and UCProfileList is a Observer and as per pattern definition when observer initialized it knows who is my Subject/Observable and add itself into Subject/Observable list. So whenever a change occurred in Subject/Observable it will be notified.
This pattern best fit my requirements but I'm getting few problems to implement this describe as follows.
I'm working under CMS (Umbraco) and I don't have any physical container page (.aspx). What I've to do is find UCCreateProfile (Subject/Observable) in UCProfileList (Observer) onLoad event using following code.
private Control FindCreateProfileControl()
{
Control control = null;
Control frm = GetFormInstance();
control = GetControlRecursive(frm.Controls);
return control;
}
where GetFormInstance() method is
private Control GetFormInstance()
{
Control ctrl = this.Parent;
while (true)
{
ctrl = ctrl.Parent;
if (ctrl is HtmlForm)
{
break;
}
}
return ctrl;
}
and GetControlRecursive() method is
private Control GetControlRecursive(ControlCollection ctrls)
{
Control result = null;
foreach (Control item in ctrls)
{
if (result != null) break;
if (item is UCCreateProfile)
{
result = item;
return result;
}
if (item.Controls != null)
result = GetControlRecursive(item.Controls);
}
return result;
}
this way I can find the UCCreateProfile (Subject/Observable) user control in UCProfileList (Observer) but the way to find out the (Subject/Observable) is not so fast. As you can see I need to loop through all controls and first find the HtmlForm control and then loop through all child controls under HtmlForm control and find the appropriate control we're looking for.
Secondly, placement of the user controls in container if very important my code will only work if UCCreatedProfile.ascx (Subject/Observable) placed before UCProfileList.ascx (Observer) because this way UCCreateProfile will load first and find in UCProfileList. But if someone changed the position of these 2 controls my code will not work.
So to get rid of these problems I need some solution which works faster and independent of the position of the controls.
I've figured out some solution as described below. Please do let me know if it is a good way of doing this. If there is an alternative, please let me know.
I've a session level variable (a dictionary with Dictionary<ISubject, List<Observer>>) . No matter which user control initialized/loaded first, User Control will add itself into this dictionary.
If Subject/Observable added first, the corresponding observers will be found in this dictionary.
If Observer added first it will added to the dictionary with a null entry. When the Subject added, the association is made.
Regards,
/Rizwan
The Observer pattern is best implemented in .NET via events and delegates. If you use events and delegates, the Dictionary you mention becomes completely unnecessary. See for example this code below (only important pieces shown):
public partial class UserProfile : System.Web.UI.UserControl
{
//This is the event handler for when a user is updated on the UserProfile Control
public event EventHandler<UserUpdatedEventArgs> UserUpdated;
protected void btnUpdate_Click(object sender, EventArgs e)
{
//Do whatever you need above and then see who's subscribed to this event
var userUpdated = UserUpdated;
if (userUpdated != null)
{
//Initialize UserUpdatedEventArgs as you want. You can, for example,
//pass a "User" object if you have one
userUpdated(this,new UserUpdatedEventArgs({....}));
}
}
}
public class UserUpdatedEventArgs : EventArgs
{
public User UserUpdated {get;set;}
public UserUpdatedEventArgs (User u)
{
UserUpdated=u;
}
}
Now subscribing to the UserUpdated event from the UserProfile control on the UserListControl is as easy as this:
public partial class UserList : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//Find the UserProfile control in the page. It seems that you already have a
//recursive function that finds it. I wouldn't do that but that's for another topic...
UserProfile up = this.Parent.FindControl("UserProfile1") as UserProfile;
if(up!=null)
//Register for the event
up.UserUpdated += new EventHandler<UserUpdatedEventArgs>(up_UserUpdated);
}
//This will be called automatically every time a user is updated on the UserProfile control
protected void up_UserUpdated(object sender, UserUpdatedEventArgs e)
{
User u = e.UserUpdated;
//Do something with u...
}
}
I am trying to make a validator that will make sure that at least 2 items are selected. The validator works correctly on the server side but the client side code never gets executed.
Here is the code:
Sys.Mvc.ValidatorRegistry.validators["country"] = function (rule) {
var min = rule.ValidationParameters["min"];
return function (value, context) {
if (value >= min) return true;
return rule.ErrorMessage;
};
};
And here is the validator code:
public class CountryValidator : DataAnnotationsModelValidator<CustomValidations.CountryAttribute>
{
private int _minimum;
private string _message;
public CountryValidator(ModelMetadata metadata, ControllerContext context, CustomValidations.CountryAttribute attribute) : base(metadata,context,attribute)
{
_minimum = attribute.Minimum;
_message = attribute.ErrorMessage;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = _message,
ValidationType = "country"
};
rule.ValidationParameters.Add("min", _minimum);
return new[] { rule };
}
}
I have even registered the validation adapter in global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(AgeAttribute), typeof(AgeValidator));
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CountryAttribute),typeof(CountryValidator));
}
I am thinking that the validator only works with the elements that have a value property like textboxes etc.
UPDATE 1:
EnableClientValidation is invoked correctly and all the required JS files are included in the project. It seems like I need to attach the onblur to the context. I will try that and post the results.
<% =Html.EnableClientValidation(); %> needs to be in your view somewhere. Also make sure you reference MicrosoftAjax.js and MicrosoftMvcValidation.js in the same view (before your js function).
Either your missing MicrosoftMvcAjax.js or you need to implement your custom validation in jQuery as described on Mr. Haack's website http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx.
I think it is because the default validation is invoked on the onblur event of the input textbox. And for a listbox this event was not being thrown.
I'm testing some event dispatch code in a Flex app, using FlexUnit's addAsync method for testing that events are dispatched. Great so far, I can ensure that at least one event was fired. However, I want to be a bit more detailed; I want to ensure that exactly the set of events I'm expecting are dispatched. Is there a useful test pattern (or, even, different test framework -- I'm flexible!) to accomplish this?
I tried this code, but it doesn't seem to get invoked the second time:
protected function expectResultPropertyChange(event: Event, numberOfEvents: int = 1): void {
trace("Got event " + event + " on " + event.target + " with " + numberOfEvents + " traces left...");
assertTrue(event.type == ResponseChangedEvent.RESPONSE_CHANGED);
if (numberOfEvents > 1) {
event.target.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, addAsync(expectResultPropertyChange, 1000, numberOfEvents - 1));
}
}
public function testSomething(): void {
requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, addAsync(expectResultPropertyChange, 1000, 2));
requiredQuestion.responseSelected("1", true);
requiredQuestion.responseSelected("2", true);
}
In response to the comment...
What if the event is dispatched
directly? responseSelected doesn't
trigger an asynchronous event on a
composite object, it simply dispatched
the RESPONSE_CHANGED event itself
directly. I'm not seeing how this
approach can be mocked using your
method. Mind you, I'm fuzzy on the
mock testing practice as-is, so I'm
probably missing a simple solution
here.
..in that case you don't need to use a mock or addAsync. Something like this will do:
public function testSomething(): void
{
var requiredQuestion : RequiredQuestion = new RequiredQuestion();
var callCount : int = 0;
requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, function(event : ResponseChangedEvent)
{
callCount++;
});
requiredQuestion.responseSelected("1", true);
requiredQuestion.responseSelected("2", true);
assertEquals(2, callCount);
}
This is going to be a high level example of how a similar problem could be solved using a mocked out object of whatever it is that's doing the asynchronous call. Obviously i can't see your code so i can't give you a precise example.
So, as i said in the comment, you can mock out a dependency in a class to fake asynchronous calls so that they become synchronous. Take the below class
public class RequiredQuestion extends EventDispatcher
{
private var someAsynchronousObject : IAsynchronousObject;
public function RequiredQuestion(someAsynchronousObject : IAsynchronousObject = null)
{
someAsynchronousObject = someAsynchronousObject || new AsynchronousObject();
someAsynchronousObject.addEventListener(Event.COMPLETE, asyncCallComplete);
}
public function responseSelected(id : String, flag : Boolean) : void
{
//Will asynchronously fire the Event.COMPLETE event
someAsynchronousObject.startAsynchrounsCall();
}
protected function asyncCallComplete(event : Event) : void
{
dispatchEvent(new ResponseChangedEvent(ResponseChangedEvent.RESPONSE_CHANGED));
}
}
So by default you are using the concrete class that you want to use unless someAsynchronousObjec is injected into the class via the constructor. AsycnhronousObject probably has it's own unit tests or it's in an external class so you don't really want, or need to be testing its functionality. What you can now do is create a mock object that implements IAsynchronousObject that can be used to fake its behavior. Using the ASMock framework the test could look something like this:
public function testSomething(): void
{
var mockIAsycnhronousObject : IAsynchronousObject =
IAsynchronousObject(mockRepository.createStrict( IAsynchronousObject));
SetupResult.forEventDispatcher(mockIAsycnhronousObject);
SetupResult.forCall(mockIAsycnhronousObject.startAsynchronousCall())
.dispatchEvent(new Event(Event.COMPLETE)); // all calls to the startAsynchronousCall method and dispatch the complete event everytime it's called.
mockRepository.replayAll();
var requiredQuestion : RequiredQuestion = new RequiredQuestion(mockIAsycnhronousObject);
var callCount : int = 0;
requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, function(event : ResponseChangedEvent)
{
callCount++;
});
requiredQuestion.responseSelected("1", true);
requiredQuestion.responseSelected("2", true);
assertEquals(2, callCount);
mockRepository.verifyAll();
}
This is just one example of how mocking can help you unit tests. There's a whole wealth of info out there on mocking although it is still very new to ActionScript (released in December). ASMock is based on the .net Rhino mocks so searching for Rhino mocks should throw up a lot more results if you need help.
Definitely a different way of thinking but once you get into it you tend to wonder how you got by in unit testing without them.