I am trying to arrange the input parameter of the lambda that is passed to ICallback#Regsiter<T>(Action<T>) in the (paired down) unit test sample below (see the comments in the unit test sample). I am trying to avoid having to abstract out the lambda because it's so specific and small, but I'm not sure if that's possible.
// IBus interface peek
public interface IBus {
ICallback Send(IMessage message);
}
// ICallback interface peek
public interface ICallback {
void Register<T>(Action<T> callback);
}
public enum ReturnCode { Success }
// Controller
public class FooController : AsyncController {
readonly IBus _bus;
//...
// Action being unit tested
public void BarAsync() {
_bus
.Send(ZapMessageFactory.Create())
.Register<ReturnCode>(x => {
AsyncManger.Parameters["returnCode"] = x;
});
}
public ActionResult BarCompleted(ReturnCode returnCode) {
// ...
}
}
// Controller action unit test
[TestClass]
public class FooControllerTest {
[TestMethod}
public void BarTestCanSetAsyncManagerParameterErrorCodeToSuccess() {
var fooController = ControllerUTFactory.CreateFooController();
// HOW DO I MOCK THE ACTION DELEGATE PARAMETER TO BE ReturnCode.Success
// SO I CAN DO THE ASSERT BELOW???
fooController.BarAsync();
Assert.AreEqual(ReturnCode.Success, (ReturnCode)fooController.AsyncManager.Parameters["returnCode"]);
}
}
Using the Mock<T>#Callback() is the answer:
[TestMethod}
public void BarTestCanSetAsyncManagerParameterErrorCodeToSuccess() {
var mockCallback = new Mock<ICallback>();
mockCallback
.Setup(x => x.Register(It.IsAny<ReasonCode>())
// THIS LINE IS THE ANSWER
.Callback(action => action(ReasonCode.Success));
var mockBus = new Mock<IBus>();
mockBus
.Setup(x => x.Send(It.IsAny<ZapMessage>())
.Returns(mockCallback.Object);
var fooController = new FooController(mockBus.Object);
fooController.BarAsync();
Assert.AreEqual(ReturnCode.Success, (ReturnCode)fooController.AsyncManager.Parameters["returnCode"]);
}
Related
I want to override my controllers method. Here i have overriden CreateController method of DefaultControllerFactory to return the CatalogCustomController object if request come for CatalogController.
But the problem is here that i need to pass all the dependency into controller constructor.
public class CustomControllerFactory: DefaultControllerFactory
{
public CustomControllerFactory(ICatalogModelFactory catalogModelFactory,
IProductModelFactory productModelFactory,
IControllerActivator controllerActivator, IEnumerable<IControllerPropertyActivator> propertyActivators)
:base(controllerActivator, propertyActivators)
{
this._catalogModelFactory = catalogModelFactory;
this._productModelFactory = productModelFactory;
}
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
return new CatalogCustomController(_catalogModelFactory,
_productModelFactory,
_categoryService,
}
return base.CreateController(context);
}
}
While i want to do it something like this, by modifying
ControllerContext context
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
context.ActionDescriptor.ControllerName = "CatalogCustomController";
}
return base.CreateController(context);
}
You could try register Controller into IServiceCollection, and then retrieve Controller from IServiceCollection in CreateController.
Extension method for AddControllersAsServices
public static class Extension
{
public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder)
{
var feature = new ControllerFeature();
builder.PartManager.PopulateFeature(feature);
foreach (var controller in feature.Controllers.Select(c => c.AsType()))
{
builder.Services.TryAddTransient(controller, controller);
}
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
return builder;
}
}
Register Services
services.AddMvc()
.AddControllersAsServices();
CustomControllerFactory
public class CustomControllerFactory : DefaultControllerFactory
{
public CustomControllerFactory(
IControllerActivator controllerActivator, IEnumerable<IControllerPropertyActivator> propertyActivators)
: base(controllerActivator, propertyActivators)
{
}
public override object CreateController(ControllerContext context)
{
if (context.ActionDescriptor.ControllerTypeInfo.AsType() == typeof(CatalogController))
{
return context.HttpContext.RequestServices.GetRequiredService(typeof(CatalogCustomController));
}
return base.CreateController(context);
}
}
I found a solution to do it without registering the controllers as service.
Inherit the custom controller from main one.
In custom controller factory, get the type of requested controller.
Replace the ControllerTypeInfo with the custom one
public override object CreateController(ControllerContext context)
{
Type typeOfController = context.ActionDescriptor.ControllerTypeInfo.UnderlyingSystemType;
if (typeOfController == typeof(Nop.Web.Controllers.CatalogController))
{
context.ActionDescriptor.ControllerTypeInfo = typeof(Controllers.CatalogCustomController).GetTypeInfo();
}
else if (typeOfController == typeof(Nop.Web.Areas.Admin.Controllers.ProductController))
{
context.ActionDescriptor.ControllerTypeInfo = typeof(Areas.Admin.Controllers.ProductCustomController).GetTypeInfo();
}
return base.CreateController(context);
}<pre>
ValidatorTest class having common methods for all the validations.
Test case get passed but after passing I am getting this error.
I can write extension methods which can do this job but I am not getting what is going wrong with xunit. Any help is appreciated.
namespace TestSuite.Validator
{
public abstract class ValidatorTest<TClass,TClassValidator> where TClassValidator: AbstractValidator<TClass>
{
private readonly TClassValidator _tClassValidator;
public ValidatorTest(TClassValidator validator)
{
_tClassValidator = validator;
}
public void Address_Should_ReturnValidationError_When_MandatoryFieldsAreNotPassed(TClass address, List<KeyValuePair<string, string>> expectedErrors)
{
var validationResult = _tClassValidator.Validate(address);
Assert.False(validationResult.IsValid);
foreach (var expectedError in expectedErrors)
{
Assert.Contains(validationResult.Errors, (actualError) => actualError.ErrorMessage.Equals(expectedError.Value) && actualError.ErrorCode.Equals(expectedError.Key));
}
foreach (var actualError in validationResult.Errors)
{
Assert.Contains<KeyValuePair<string, string>>(expectedErrors, expectedError => expectedError.Value.Equals(actualError.ErrorMessage) && expectedError.Key.Equals(actualError.ErrorCode));
}
}
public void Address_Should_Pass_When_MandatoryFieldsArePassed(TClass address)
{
var validationResult = _tClassValidator.Validate(address);
Assert.True(validationResult.IsValid);
Assert.Empty(validationResult.Errors);
}
}
}
namespace TestSuite.Validator
{
public class AddressValidatorTest : ValidatorTest<Address, AddressValidator>
{
public AddressValidatorTest(AddressValidator addressValidator) : base(new AddressValidator())
{
}
[Theory]
[JsonDataReaderAttribute("AddressValidatorData", "Valid")]
public void PositiveTest(Address address)
{
Address_Should_Pass_When_MandatoryFieldsArePassed(address);
}
}
}
I just had a similar error and it was because I forgot to implement IClassFixture on my test class.
My aspect:
[Serializable]
class FlowController : OnMethodBoundaryAspect
{
[ThreadStatic]
private static bool logging;
public override void OnEntry(MethodExecutionArgs args)
{
if (logging)
return;
try
{
logging = true;
if (ProgramState.State() == false)
{
args.ReturnValue = ""; // WHAT DO I SET HERE?
args.FlowBehavior = FlowBehavior.Return;
}
}
finally
{
logging = false;
}
}
}
Basically the ProgramState.State() method checks if the program is running(true),paused(loops while isPaused == true), stopped(false), this should control the if methods can run or not(basically a start pause/resume stop thing)
But sometimes i get nullreferences when returning from the method.
i am interested in knowing how can i set the return type to the default return type of the method.
It is tested with PostSharp 6.0.29
Before use it please check required null controls.
If method is async Task
public override void OnException(MethodExecutionArgs args)
{
var methodReturnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
var runtime = methodReturnType.GetRuntimeFields().FirstOrDefault(f => f.Name.Equals("m_result"));
//Only if return type has parameterless constructture (should be check before create)
var returnValue = Activator.CreateInstance(runtime.FieldType);
args.ReturnValue = returnValue;
}
And if method is not async
public override void OnException(MethodExecutionArgs args)
{
var methodReturnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
//Only if return type has parameterless constructture (should be check before create)
var returnValue = Activator.CreateInstance(methodReturnType);
args.ReturnValue = returnValue;
}
You can make your aspect class generic with the generic parameter representing the method return type. Then you need to create a method-level attribute that is also an aspect provider. The attribute will be applied to the user code and in turn it can provide the correct instance of the generic aspect.
[Serializable]
[MulticastAttributeUsage( MulticastTargets.Method )]
public class FlowControllerAttribute : MethodLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
MethodInfo method = (MethodInfo) targetElement;
Type returnType = method.ReturnType == typeof(void)
? typeof(object)
: method.ReturnType;
IAspect aspect = (IAspect) Activator.CreateInstance(typeof(FlowControllerAspect<>).MakeGenericType(returnType));
yield return new AspectInstance(targetElement, aspect);
}
}
[Serializable]
public class FlowControllerAspect<T> : IOnMethodBoundaryAspect
{
public void RuntimeInitialize(MethodBase method)
{
}
public void OnEntry(MethodExecutionArgs args)
{
args.ReturnValue = default(T);
args.FlowBehavior = FlowBehavior.Return;
}
public void OnExit(MethodExecutionArgs args)
{
}
public void OnSuccess(MethodExecutionArgs args)
{
}
public void OnException(MethodExecutionArgs args)
{
}
}
// Usage:
[FlowController]
public int Method()
{
// ...
}
I have a problem in creating class for xamarin.ios delegate.
In iOS we use protocols to implement the delegate but here I can not implement Interface as a delegate.
Let me clear this concept.
I have an interface in one file like:
public interface SendBackDelegate
{
void sendBackData();
}
public class SelectList
{
}
In other file I have main class like this:
public class ShowList: SendBackDelegate
{
public ShowList()
{
SelectList obj = new SelectList();
obj.delegate = this;
}
void sendBackData()
{
Console.WriteLine("Send Back DATA");
}
}
Now Can you please tell me how this interface be implemented in SelectList class?
Thanks
you can use Interface like protocol, only you have to make reference object of interfaces it can own the class object which already implemented the Interface methods. it will be clear with your example as well.
public interface SendBackDelegate
{
void sendBackData();
}
public class SelectList
{
ShowList showListObj = new ShowList();
SendBackDelegate delegate = showListObj;
delegate.sendBackData();
//this will call the method sendBackData() of class ShowList.
}
public class ShowList: SendBackDelegate
{
public ShowList()
{
SelectList obj = new SelectList();
obj.delegate = this;
}
void sendBackData()
{
Console.WriteLine("Send Back DATA");
}
}
Please let me know if you still have questions.
I am not using delegates anymore on Xamarin.iOS. I prefer to use actions though.
class MainClass
{
public static void Main (string[] args)
{
var x = new ShowList ();
}
}
public interface SendBackDelegate
{
void sendBackData ();
}
public class ShowList : SendBackDelegate
{
public ShowList ()
{
SelectList obj = new SelectList (sendBackData);
}
public void sendBackData ()
{
Console.WriteLine ("Send Back DATA");
}
}
public class SelectList
{
Action _callback;
public SelectList (Action callback)
{
_callback = callback;
Ticker ();
}
private void Ticker ()
{
_callback ();
}
}
Trying to model a system sending out notifications from a number of publishers using RX.
I have two custom interfaces ITopicObservable and ITopicObserver to model the fact that the implementing classes will have other properties and methods apart from the IObservable and IObserver interfaces.
The problem I have is that my thinking is I should be able to add a number of observables together, merge them together and subscribe to an observer to provide updates from all merged observables. However the code with "the issue" comment throws an invalid cast exception.
The use case is a number of independent sensors each monitoring a temperature in a box for example that aggregate all their reports to one temperature report which is then subscribed to by a temperature health monitor.
What am I missing here? Or is there a better way to implement the scenario using RX?
Code below
using System;
using System.Reactive.Linq;
using System.Collections.Generic;
namespace test
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
var to = new TopicObserver ();
var s = new TopicObservable ("test");
var agg = new AggregatedTopicObservable ();
agg.Add (s);
agg.Subscribe (to);
}
}
public interface ITopicObservable<TType>:IObservable<TType>
{
string Name{get;}
}
public class TopicObservable:ITopicObservable<int>
{
public TopicObservable(string name)
{
Name = name;
}
#region IObservable implementation
public IDisposable Subscribe (IObserver<int> observer)
{
return null;
}
#endregion
#region ITopicObservable implementation
public string Name { get;private set;}
#endregion
}
public class AggregatedTopicObservable:ITopicObservable<int>
{
List<TopicObservable> _topics;
private ITopicObservable<int> _observable;
private IDisposable _disposable;
public AggregatedTopicObservable()
{
_topics = new List<TopicObservable>();
}
public void Add(ITopicObservable<int> observable)
{
_topics.Add ((TopicObservable)observable);
}
#region IObservable implementation
public IDisposable Subscribe (IObserver<int> observer)
{
_observable = (ITopicObservable<int>)_topics.Merge ();
_disposable = _observable.Subscribe(observer);
return _disposable;
}
#endregion
#region ITopicObservable implementation
public string Name { get;private set;}
#endregion
}
public interface ITopicObserver<TType>:IObserver<TType>
{
string Name{get;}
}
public class TopicObserver:ITopicObserver<int>
{
#region IObserver implementation
public void OnNext (int value)
{
Console.WriteLine ("next {0}", value);
}
public void OnError (Exception error)
{
Console.WriteLine ("error {0}", error.Message);
}
public void OnCompleted ()
{
Console.WriteLine ("finished");
}
#endregion
#region ITopicObserver implementation
public string Name { get;private set;}
#endregion
}
}
My first thought, is that you shouldn't implement IObservable<T>, you should compose it by exposing it as a property or the result of a method.
Second thought is that there are operators in Rx that excel at merging/aggregating multiple sequences together.
You should favor using those.
Third, which is similar to the first, you generally don't implement IObserver<T>, you just subscribe to the observable sequence and provide delegates for each call back (OnNext, OnError and OnComplete)
So your code basically is reduced to
Console.WriteLine("Hello World!");
var topic1 = TopicListener("test1");
var topic2 = TopicListener("test2");
topic1.Merge(topic2)
.Subscribe(
val => { Console.WriteLine("One of the topics published this value {0}", val);},
ex => { Console.WriteLine("One of the topics errored. Now the whole sequence is dead {0}", ex);},
() => {Console.WriteLine("All topics have completed.");});
Where TopicListener(string) is just a method that returns IObservable<T>.
The implementation of the TopicListener(string) method would most probably use Observable.Create.
It may help to see examples of mapping Rx over a Topic based messaging system.
There is an example of how you can layer Rx over TibRv topics here https://github.com/LeeCampbell/RxCookbook/blob/master/IO/Comms/TibRvSample.linq
The signature of the .Merge(...) operator that you're using is:
IObservable<TSource> Merge<TSource>(this IEnumerable<IObservable<TSource>> sources)
The actual type returned by this .Merge() is:
System.Reactive.Linq.ObservableImpl.Merge`1[System.Int32]
...so it should be fairly clear that calling (ITopicObservable<int>)_topics.Merge(); would fail.
Lee's advice not to implement either of IObservable<> or IObserver<> is the correct one. It leads to errors like the one above.
If you had to do something like this, I would do it this way:
public interface ITopic
{
string Name { get; }
}
public interface ITopicObservable<TType> : ITopic, IObservable<TType>
{ }
public interface ITopicSubject<TType> : ISubject<TType>, ITopicObservable<TType>
{ }
public interface ITopicObserver<TType> : ITopic, IObserver<TType>
{ }
public class Topic
{
public string Name { get; private set; }
public Topic(string name)
{
this.Name = name;
}
}
public class TopicSubject : Topic, ITopicSubject<int>
{
private Subject<int> _subject = new Subject<int>();
public TopicSubject(string name)
: base(name)
{ }
public IDisposable Subscribe(IObserver<int> observer)
{
return _subject.Subscribe(observer);
}
public void OnNext(int value)
{
_subject.OnNext(value);
}
public void OnError(Exception error)
{
_subject.OnError(error);
}
public void OnCompleted()
{
_subject.OnCompleted();
}
}
public class AggregatedTopicObservable : Topic, ITopicObservable<int>
{
List<ITopicObservable<int>> _topics = new List<ITopicObservable<int>>();
public AggregatedTopicObservable(string name)
: base(name)
{ }
public void Add(ITopicObservable<int> observable)
{
_topics.Add(observable);
}
public IDisposable Subscribe(IObserver<int> observer)
{
return _topics.Merge().Subscribe(observer);
}
}
public class TopicObserver : Topic, ITopicObserver<int>
{
private IObserver<int> _observer;
public TopicObserver(string name)
: base(name)
{
_observer =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
}
public void OnNext(int value)
{
_observer.OnNext(value);
}
public void OnError(Exception error)
{
_observer.OnError(error);
}
public void OnCompleted()
{
_observer.OnCompleted();
}
}
And run it with:
var to = new TopicObserver("watching");
var ts1 = new TopicSubject("topic 1");
var ts2 = new TopicSubject("topic 2");
var agg = new AggregatedTopicObservable("agg");
agg.Add(ts1);
agg.Add(ts2);
agg.Subscribe(to);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
Which gives:
next 42
next 1
finished
But apart from being able to give everything a name (which I'm not sure how it helps) you could always do this:
var to =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
var ts1 = new Subject<int>();
var ts2 = new Subject<int>();
var agg = new [] { ts1, ts2 }.Merge();
agg.Subscribe(to);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
Same output with no interfaces and classes.
There's even a more interesting way. Try this:
var to =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
var agg = new Subject<IObservable<int>>();
agg.Merge().Subscribe(to);
var ts1 = new Subject<int>();
var ts2 = new Subject<int>();
agg.OnNext(ts1);
agg.OnNext(ts2);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
var ts3 = new Subject<int>();
agg.OnNext(ts3);
ts3.OnNext(99);
ts3.OnCompleted();
This produces:
next 42
next 1
next 99
It allows you to add new source observables after the merge!