How to Moq this view? - c#

I have a view for which I'd like to mock the Show behaviour.
Once the credentials have been entered, the [Connecter] button enables itself, and then the user can click. I wish I could reproduce this behaviour without having to show the view and actually really enter my credentials.
The application is a WinForms MDI presented by the IApplicationPresenter. The IApplicationPresenter raises the ShowView to which the IApplicationView subscribed.
Then, when the IApplicationView.Shown, the IApplicationPresenter forces the user to authenticate like this:
IApplicationPresenter.OnViewShown
public void OnViewShown() { forceAuthentication(); }
private void forceAuthentication() {
IAuthenticationView authView = new AuthenticationView();
IAuthenticationPrenseter authPresenter = new AuthenticationPresenter();
authPresenter.ShowView();
}
It's like I can smell one thing.
It's just like I could inject the IAuthenticationView to the IApplicationPresenter. Then, this would allow me to inject my mocked view to it, and avoid the view being actually shown, which is in fact what I want to come up with. Is it the best way to make it?
Now, I want to test that when the IApplicationView is shown, the IApplicationPresenter is notified and forces authentication.
Any thoughts of a better approach in terms of mocking here?
UPDATE
IView
public interface IView {
void CloseView();
void SetTitle(string title);
void ShowView();
void RaiseVoidEvent(VoidEventHandler #event);
event VoidEventHandler OnViewInitialize;
event VoidEventHandler OnViewShown;
}
IApplicationView
public interface IApplicationView : IView {
void OnUserAuthenticated();
event VoidEventHandler ManageRequestsClicked;
}
IPresenter
public interface IPresenter<V> where V : IView {
V View { get; }
IDatabaseUser CurrentUser { get; }
void CloseView();
void OnViewInitialize();
void RaiseVoidEvent(VoidEventHandler #event);
void ShowView();
event VoidEventHandler OnCloseView;
event VoidEventHandler OnShowView;
}
Presenter
public abstract class Presenter<V> : IPresenter<V> where V : IView {
public Presenter(V view) {
if (view == null) throw new ArgumentNullException("view");
View = view;
View.OnViewInitialize += OnViewInitialize;
OnCloseView += View.CloseView;
OnShowView += View.ShowView;
}
public virtual IDatabaseUser CurrentUser { get; protected set; }
public virtual V View { get; private set; }
public virtual void CloseView() { RaiseVoidEvent(OnCloseView); }
public virtual void OnViewInitialize() { }
public void RaiseVoidEvent(VoidEventHandler #event) { if (#event != null) #event(); }
public virtual void ShowView() { RaiseVoidEvent(OnShowView); }
public virtual event VoidEventHandler OnCloseView;
public virtual event VoidEventHandler OnShowView;
}
IApplicationPresenter
public interface IApplicationPresenter : IPresenter<IApplicationView> {
IAuthenticationPresenter AuthenticationPresenter { get; set; }
void OnManageRequestsClicked();
void OnUserAuthenticated(UserAuthenticatedEventArgs e);
void OnViewShown();
}
ApplicationPresenter
public class ApplicationPresenter : Presenter<IApplicationView>, IApplicationPresenter {
public ApplicationPresenter(IApplicationView view) : this(view, null) { }
public ApplicationPresenter(IApplicationView view, IAuthenticationPresenter authPresenter) : base(view) {
AuthenticationPresenter = authPresenter;
View.OnViewShown += OnViewShown;
View.ManageRequestsClicked += OnManageRequestsClicked;
}
public IAuthenticationPresenter AuthenticationPresenter { get { return authenticationPresenter; } set { setAuthenticationPresenter(value); } }
public void OnManageRequestsClicked() {
var requests = new GestionDemandeAccesInformationForm();
requests.Database = database;
requests.MdiParent = (System.Windows.Forms.Form)View;
requests.Show();
}
public void OnUserAuthenticated(UserAuthenticatedEventArgs e) {
CurrentUser = new DatabaseUser(e.Login, e.Password, e.DatabaseInstance);
database = new DatabaseSessionFactory(CurrentUser);
setAppTitle();
showRequestsManagementView();
}
public void OnViewShown() { forceAuthentication(); }
}
IAuthenticationView
public interface IAuthenticationView : IView {
string ErrorMessage { get; set; }
string Instance { get; set; }
IEnumerable<string> Instances { get; set; }
string Login { get; set; }
string Password { get; set; }
void EnableConnectButton(bool enabled);
void SetDefaultInstance(string defaultInstance);
void RaiseSelectionChangedEvent(SelectionChangedEventHandler #event, SelectionChangedEventArgs e);
event VoidEventHandler OnConnect;
event SelectionChangedEventHandler OnDatabaseInstanceChanged;
event VoidEventHandler OnLoginChanged;
event VoidEventHandler OnPasswordChanged;
}
IAuthenticationPresenter
public interface IAuthenticationPresenter : IValidatablePresenter, IPresenter<IAuthenticationView> {
void OnConnect();
void OnViewDatabaseInstanceChanged(SelectionChangedEventArgs e);
void OnViewLoginChanged();
void OnViewPasswordChanged();
void RaiseUserAuthenticatedEvent(UserAuthenticatedEventArgs e);
event UserAuthenticatedEventHandler UserAuthenticated;
}
AuthenticationPresenter
public class AuthenticationPresenter : Presenter<IAuthenticationView>, IAuthenticationPresenter {
public AuthenticationPresenter(IAuthenticationView view, IMembershipService service) : base(view) {
MembershipService = service;
View.ErrorMessage = null;
View.SetTitle(ViewTitle);
subscribeToEvents();
}
public bool IsValid { get { return credentialsEntered(); } }
public IMembershipService MembershipService { get; set; }
public virtual void OnConnect() {
if (noDatabaseInstanceSelected()) display(MissingInstanceErrorMessage);
else if (noLoginEntered()) display(MissingLoginErrorMessage);
else if (noPasswordEntered()) display(MissingPasswordErrorMessage);
else {
display(EverythingIsFine);
if (isAuthenticUser()) notifyTheApplicationThatTheUserIsAuthentic();
else { display(InvalidLoginOrPasswordErrorMessage); }
}
}
public override void OnViewInitialize() {
base.OnViewInitialize();
View.ErrorMessage = null;
View.Instances = Configuration.DatabaseInstances;
View.SetDefaultInstance(Configuration.DefaultInstance);
}
public void OnViewDatabaseInstanceChanged(SelectionChangedEventArgs e) { View.Instance = (string)e.Selected; }
public void OnViewLoginChanged() { View.EnableConnectButton(IsValid); }
public void OnViewPasswordChanged() { View.EnableConnectButton(IsValid); }
public void RaiseUserAuthenticatedEvent(UserAuthenticatedEventArgs e) { if (UserAuthenticated != null) UserAuthenticated(e); }
public event UserAuthenticatedEventHandler UserAuthenticated;
}

If I were you, I'd inject a factory for creating AuthenticationPresenter and in your test I would call OnViewShown() and verify on your mock (of the presenter returned by the factory) that ShowView is called.
EDIT
Note that I haven't compiled this, I don't have a C# compiler right now.
Here is my version of the test. Based on my interpretation of what you really want to test :
[TestClass]
public class ApplicationPresenterTests
{
[TestClass]
public class OnViewShown : ApplicationPresenterTests
{
[TestMethod]
public void ForceAuthentication()
{
// given
var authenticationPresenterFactory = new Mock<IAuthenticationPresenterFactory>();
var authenticationPresenter = new Mock<IAuthenticationPresenter>();
authenticationPresenterFactory.Setup(f => f.create()).Returns(authenticationPresenter.Object);
var presenter = new ApplicationPresenter(authenticationPresenterFactory);
// when
presenter.OnViewShown();
// then
authenticationPresenter.Verify(p => p.ShowView());
}
}

So far, I have come up with this solution which works flawlessly.
It's all about setting up the mock object to work as expected.
[TestClass]
public abstract class ApplicationPresenterTests {
[TestClass]
public class OnViewShown : ApplicationPresenterTests {
[TestMethod]
public void ForceAuthentication() {
// arrange
// act
Presenter.OnViewShown();
var actual = Presenter.CurrentUser;
// assert
Assert.IsNotNull(actual);
Assert.IsInstanceOfType(actual, typeof(IDatabaseUser));
}
}
[TestInitialize]
public void ApplicationMainPresenterSetUp() {
Mock<IAuthenticationView> authView = new Mock<IAuthenticationView>(MockBehavior.Strict);
authView.SetupProperty(v => v.ErrorMessage);
authView.SetupGet(v => v.Instance).Returns(RandomValues.RandomString());
authView.SetupGet(v => v.Login).Returns(RandomValues.RandomString());
authView.SetupGet(v => v.Password).Returns(RandomValues.RandomString());
authView.Setup(v => v.CloseView());
authView.Setup(v => v.SetTitle(It.IsAny<string>()));
authView.Setup(v => v.ShowView()).Raises(v => v.OnConnect += null).Verifiable();
Mock<IMembershipService> authService = new Mock<IMembershipService>(MockBehavior.Loose);
authService.Setup(s => s.AuthenticateUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(true);
IAuthenticationPresenter authPresenter = new AuthenticationPresenter(authView.Object, authService.Object);
ApplicationView = new ApplicationForm();
Presenter = new ApplicationPresenter(ApplicationView, authPresenter);
}
protected IApplicationView ApplicationView { get; private set; }
protected IApplicationPresenter Presenter { get; private set; }
}
Therefore, the key change was to inject the dependancy of an IAuthenticationPresenter into the IApplicationPresenter, hence the ApplicationPresenter constructor overload.
Though this has solved my problem, I better understand the need for a PresenterFactory being injected into the ApplicationPresenter, since this is the presenter which handles everything in the application, that is, the calls to other views for each which has its own presenter.
Before me lies an even more complex challenge to take on. Stay tuned!

Related

Invoke parent function in derived nested class

How to invoke function Run() from Controller class in class I2C?
class Program
{
public class Controller
{
public void Run()
{
}
}
public class ChildController : Controller
{
}
public class LowLevelController : ChildController
{
private class I2C
{
public I2C()
{
}
// Want to call Controller.Run() from this level
}
public void Computate()
{
base.Run();
}
}
}
Option 1
One way to achieve this would be exposing method in I2C which accepts an Action. This would allow the instance of I2C, which is a private class defined within LowLevelController to invoke Controller.Run. For example,
private class I2C
{
public I2C()
{
}
public void RunBase(Action execute)
{
execute.Invoke();
}
}
Now you could execute the RunBase as
public void Computate()
{
var i2c = new I2C();
i2c.RunBase(()=>base.Run());
}
Option 2
The other option would be to pass an instance of LowLevelController to I2C and invoke the Controller.Run method
Example,
public class LowLevelController : ChildController
{
private class I2C
{
private LowLevelController _parent;
public I2C(LowLevelController parent)
{
_parent = parent;
}
public void RunBase()
{
_parent.Run();
}
}
public void Computate()
{
var i2c = new I2C(this);
i2c.RunBase();
}
}
I think what you want is simply:
public class LowLevelController : ChildController {
private class I2C {
public I2C(LowLevelController outerInstance) {
OuterInstance = outerInstance;
}
private LowLevelController OuterInstance { get; }
private void DoSomething() {
OuterInstance.Run();
}
}
}

Copy constructor in polymorphism in C#

Please first take a look at this simple code;
This is my base class:
public class BaseClass
{
public BaseClass()
{
}
public BaseClass(BaseClass b)
{
}
public virtual string GetMSG()
{
return "Base";
}
}
and this is the derived one:
public class DrivenClass : BaseClass
{
public string MSG { get; set; }
public DrivenClass(string msg)
{
MSG = msg;
}
public DrivenClass(DrivenClass d)
{
MSG = d.MSG;
}
public override string GetMSG()
{
return MSG;
}
}
and this is the test:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public BaseClass B { get; set; }
public DrivenClass D { get; set; }
private void button1_Click(object sender, EventArgs e)
{
D = new DrivenClass("Driven");
B = new BaseClass(D);
MessageBox.Show("B:" + B.GetMSG() + "\nD:" + D.GetMSG());
}
}
Now my question is what should I do that B = new BaseClass(D); works like B = new DrivenClass(D); ?
I'm using this in polymorphism and I like to use one copy-constructor instead of different driven ones.
I want the output like this :
Driven
Driven
but now it's like this :
Base
Driven
You can use an overridden virtual Copy method instead of a copy constructor.
public class BaseClass
{
public BaseClass()
{
}
public virtual BaseClass ShallowCopy()
{
return new BaseClass();
}
public virtual string GetMSG()
{
return "Base";
}
}
public class DrivenClass : BaseClass
{
public string MSG { get; set; }
public DrivenClass(string msg)
{
MSG = msg;
}
public override BaseClass ShallowCopy() {
return new DrivenClass(this.MSG);
}
public override string GetMSG()
{
return MSG;
}
}
Then call it like this:
D = new DrivenClass("Driven");
B = D.ShallowCopy();
This will work because calling a virtual method always calls the actual overriden implementation in the subclass, even when called from the baseclass interface.
What happens is normal because you create new instance of base class here. Therefore you never override the GetMSG method:
B = new BaseClass(D);
What you wanted to do is to have the same public class:
public BaseClass B { get; set; }
and to give it the value of new DrivenClass(D)
B = new DrivenClass(D);

Is there a standard pattern for creating worker classes with access to protected members?

I just did something kind of wacky using a partial class and I'm wondering if there's an already established pattern that might have accomplished the same thing using a less confusing approach.
The problem:
I had a base class with protected members and virtual methods designed for the derived class to do work when they are called.
I wanted to delegate this work out to a list of workers.
However I needed the workers to have access to the protected members.
My probably overly complicated solution:
Note: I realize this depends on the class being partial - I'm OK with that but it would be cool if there was a solution that didn't need it...
void Main()
{
ABase aBase = new ADerived();
aBase.DoWork();
}
public partial class ABase
{
protected int state1 = 1;
protected int state2 = 2;
List<ABase> workers;
public ABase()
{
workers = new List<ABase>();
CreateWorkers(workers);
}
protected virtual void CreateWorkers(List<ABase> workers)
{
}
public ABase(ABase aBase)
{
this.Target = aBase;
}
public virtual void DoWork()
{
foreach (var worker in this.workers)
{
worker.DoWork();
}
}
protected ABase Target { get; private set; }
}
public partial class ABase
{
public class Worker1 : ABase
{
public Worker1(ABase aBase) : base(aBase) { }
public override void DoWork()
{
Console.WriteLine (Target.state1);
}
}
public class Worker2 : ABase
{
public Worker2(ABase aBase) : base(aBase) { }
public override void DoWork()
{
Console.WriteLine (Target.state2);
}
}
}
public class ADerived : ABase
{
protected override void CreateWorkers(List<ABase> workers)
{
workers.Add(new Worker1(this));
workers.Add(new Worker2(this));
}
}
Output:
1
2
I would change the design so that the workers weren't accessing instance fields at all. I would have DoWork take a parameter with the information that they need and have the base class pass the state into the DoWork method.
public class MyState //TODO give better name
{
public int State1 { get; set; }
public int State2 { get; set; }
}
public class ABase
{
public MyState state = new MyState()
{
State1 = 1,
State2 = 2
};
List<Action<MyState>> workers = new List<Action<MyState>>();
public ABase()
{
CreateWorkers();
}
public void DoWork()
{
foreach (var action in workers)
{
action(state);
}
}
private void CreateWorkers()
{
workers.Add(new Worker1().DoWork);
workers.Add(Worker2.Process);
}
}
public class Worker1
{
public void DoWork(MyState state)
{
Console.WriteLine(state.State1);
}
}
public class Worker2
{
public static void Process(MyState state)
{
Console.WriteLine(state.State2);
}
}

Populate Combobox and DataGridView using MVP

how populate ComboBox and DataGridView using MVP (Model-View-Presenter). Actually i have something like this:
The View base class:
public interface IView
{
event EventHandler Initialize;
event EventHandler Load;
}
The presenter base class:
public class Presenter<TView> where TView : class, IView
{
private TView view;
public TView View { get { return view; } private set { view = value; } }
public Presenter(TView view)
{
if (view == null)
throw new ArgumentNullException("view");
View = view;
View.Initialize += OnViewInitialize;
View.Load += OnViewLoad;
}
protected virtual void OnViewInitialize(object sender, EventArgs e) { }
protected virtual void OnViewLoad(object sender, EventArgs e) { }
}
The specific view:
public interface IAdministrarUsuariosView : IView
{
string NombreUsuarioABuscar {get; set;}
List<Perfil> ListaPerfiles {get; set;}
event EventHandler BuscarUsuarioPorNombre;
event EventHandler BuscarUsuarioPorPerfil;
}
I don't know how to populate the ComboBox and the Datagridview!
PD: Thanks to Josh for the code of the View and Presenter base classes (MVP Base Class)
Thanks!!
you need to create a property that you will use to set up the data source for the ComboBox and DropdownList.
just to give you an example(you need to improve this code but it shows a way on how you can do that)
in you view :
//this is just a template to simulate a datasource item
public class TestItem
{
public int Id { get; set; }
public string Description { get; set; }
}
public interface IAdministrarUsuariosView : IView
{
string NombreUsuarioABuscar { get; set; }
// List<Perfil> ListaPerfiles { get; set; }
event EventHandler BuscarUsuarioPorNombre;
event EventHandler BuscarUsuarioPorPerfil;
List<TestItem> SetComboBox { set; }
List<TestItem> SetGridView { set; }
}
then in the concrete view (the winform that imolements the IAdministrarUsuariosView
public class YourView:IAdministrarUsuariosView
{
public string NombreUsuarioABuscar
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public event EventHandler BuscarUsuarioPorNombre;
public event EventHandler BuscarUsuarioPorPerfil;
public List<TestItem> SetComboBox
{
set
{
ComboBox.DataSource = value;
//your need to specify value and text property
ComboBox.DataBind();
}
}
public List<TestItem> SetGridView
{
set
{
GridView.DataSource = value;
//your need to specify value and text property
GridView.DataBind();
}
}
}
then your presenter should look like the below:
public class YourPresenter:Presenter<IAdministrarUsuariosView>
{
public YourPresenter(IAdministrarUsuariosView view) : base(view)
{
}
protected override void OnViewLoad(object sender, EventArgs e)
{
List<TestItem> listResult = GetListItem();
this.View.SetComboBox = listResult;
this.View.SetGridView = listResult;
}
}

Understanding Domain Events

I am trying to understand the domain events. Let's say I have a customer object and it raises the OnCustomerInserted event. I want my email service class to subscribe to that event so that whenever the event is raised an email is sent.
public class Customer
{
public delegate void CustomerInsertedHandler();
public event CustomerInsertedHandler CustomerInserted;
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public void OnCustomerInserted()
{
if(CustomerInserted != null)
{
CustomerInserted();
}
}
}
And here is the CustomerRepository:
public class CustomerRepository
{
public void Add(Customer customer)
{
// add the customer
customer.Id = 2;
if(customer.Id > 0)
{
// raise the event!
}
}
}
Finally, here is the simple EmailService class:
public class EmailService
{
public EmailService()
{
}
public void Send()
{
Console.WriteLine("Email has been sent!");
}
}
UPDATE:
Still the code below is bit ugly!
public class CustomerRepository
{
public delegate void CustomerInsertedHandler(Customer newCustomer);
public event CustomerInsertedHandler CustomerInserted;
public void OnCustomerInserted(Customer newCustomer)
{
if (CustomerInserted != null)
CustomerInserted(newCustomer);
}
public void Add(Customer customer)
{
// add the customer
customer.Id = 2;
if(customer.Id > 0)
{
var emailService = new EmailService();
CustomerInserted += emailService.Send;
// raise the event!
OnCustomerInserted(customer);
}
}
}
I updated my repository and is using StructorMap to create instance of the Repository
public class CustomerRepository : ICustomerRepository
{
public delegate void CustomerInsertedHandler(Customer newCustomer);
public event CustomerInsertedHandler CustomerInserted;
private IEmailService _emailService;
public CustomerRepository(IEmailService emailService)
{
_emailService = emailService;
CustomerInserted += _emailService.Send;
}
The code is still not good since now the CustomerRepository constructor is getting crowded. The EmailService is clean as follows:
public class EmailService : IEmailService
{
public EmailService()
{
}
public void Send(Customer customer)
{
Console.WriteLine("Email Sent!");
}
}
Udi Dahan has a good example on his blog: http://www.udidahan.com/2008/08/25/domain-events-take-2/.
The basic idea is to create an Event as a first class object in your domain model. Then whoever needs to can subscribe to the event, and also publish it.
Move CustomerInserted from Customer to CustomerRepository and you'll be just fine. And tweak CustomerInsertedHandler so that it will contain a reference to the inserted Customer object:
public delegate void CustomerInsertedHandler(Customer insertedCustomer);
Or do it more in line with the rest of .NET:
public delegate void CustomerInsertedHandler(object sender, CustomerInsertedEventArgs e);
So the overall structure will be as follows:
public delegate void CustomerInsertedHandler(Customer newCustomer);
public class CustomerRepository
{
public event CustomerInsertedHandler CustomerInserted;
private void RaiseCustomerInserted(Customer newCustomer)
{
if(CustomerInserted != null)
CustomerInserted(newCustomer);
}
public void Add(Customer customer)
{
// add the customer
customer.Id = 2;
if(customer.Id > 0)
RaiseCustomerInserted(customer);
}
}
public class EmailService
{
// Using autoproperty syntax from C# 3.0
public CustomerRepository { get; set; }
public EmailService()
{
}
public void Initialize()
{
//
// You need to get hold of a reference to CustomerRepository somehow.
// Google for either "Dependency Injection" or "Service Locator".
CustomerRepository.CustomerInserted += delegate(Customer c)
{ Send(c); };
}
public void Send(Customer customer)
{
Console.WriteLine("Email has been sent to " + customer.Name);
}
}

Categories

Resources