Unit Test a CSLA Asynchronous Validation Rule - unit-testing

I have a validation rule on a CSLA Business Base stereotyped class. I'm having trouble figuring out how to unit test the validation rule as it includes an asynchronous callback lambda expression. Here's some example code:
using System;
using System.Collections.Generic;
using Csla;
using Csla.Validation;
namespace UnitTestCSLAAsyncValidationRule
{
public class BusinessObject : BusinessBase<BusinessObject>
{
protected static PropertyInfo<string> CodeProperty = RegisterProperty<string>(p => p.Code);
public string Code
{
get { return GetProperty(CodeProperty); }
set { SetProperty(CodeProperty, value); }
}
protected override void AddBusinessRules()
{
ValidationRules.AddRule(CodeValidator, new AsyncRuleArgs(CodeProperty));
}
public static void CodeValidator(AsyncValidationRuleContext context)
{
var code = (string) context.PropertyValues["Code"];
CodeList codeList;
CodeList.GetCodeList((o, l) =>
{
codeList = l.Object;
if (codeList.Contains(code))
{
context.OutArgs.Result = false;
context.OutArgs.Description = "Code already in use.";
}
else
{
context.OutArgs.Result = true;
}
});
context.Complete();
}
}
public class CodeList : List<string>
{
public static void GetCodeList(EventHandler<DataPortalResult<CodeList>> handler)
{
DataPortal<CodeList> dp = new DataPortal<CodeList>();
dp.FetchCompleted += handler;
dp.BeginFetch();
}
private void DataPortal_Fetch()
{
// some existing codes..
Add("123");
Add("456");
}
}
}
I would like to test this with a test similar to the following:
using NUnit.Framework;
namespace UnitTestCSLAAsyncValidationRule.Test
{
[TestFixture]
public class BusinessObjectTest
{
[Test]
public void CodeValidationTest()
{
var bo = new BusinessObject();
bo.Code = "123";
Assert.IsNotEmpty(bo.BrokenRulesCollection);
}
}
}
However, the test Assert runs before the async callback. Is this something UnitDriven could help with? I've had a look at it but can't see how to use it in this scenario.
Thanks,
Tom

Answered by JonnyBee on http://forums.lhotka.net/forums/p/10023/47030.aspx#47030:
using NUnit.Framework;
using UnitDriven;
namespace UnitTestCSLAAsyncValidationRule.Test
{
[TestFixture]
public class BusinessObjectTest : TestBase
{
[Test]
public void CodeValidationTest()
{
UnitTestContext context = GetContext();
var bo = new BusinessObject();
bo.ValidationComplete += (o, e) =>
{
context.Assert.IsFalse(bo.IsValid);
context.Assert.Success();
//Assert.IsNotEmpty(bo.BrokenRulesCollection);
};
bo.Code = "123";
context.Complete();
}
}
}
Please not there was a small bug in my validation rule method - the call to AsyncValidationRuleContext.Complete() needs to be inside the lambda.
Thanks,
Tom

Related

In SOAP message to WCF web service, how to put KeyIdentifier directly inside SecurityTokenReference (inline, without using Reference token)

I'm successful in communicating with a WCF service via SoapUI (I was given specification on how to configure it), but I'm having trouble in copying those settings to .NET application. Turns out the shape of generated SOAP message (peeked via Fiddler) is being rejected by the web service, who expects a stricter layout of envelope.
I'm very close. On this picture...
... you can see three SOAP messages:
1. With X509SecurityTokenParameters.InclusionMode set to AlwaysToRecipient
2. With X509SecurityTokenParameters.InclusionMode set to Never
3. Expected security token, tested on SoapUI.
How do I achieve envelope from point 3 using C# code? I'm not using app.config file, entire config is inside C# code (but I'm not dedicated on keeping it that way, it just happened). Current code:
using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
using System.Text;
public class CustomAlgorithmSuite : SecurityAlgorithmSuite
{
public override string DefaultAsymmetricKeyWrapAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
public override string DefaultAsymmetricSignatureAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
public override string DefaultCanonicalizationAlgorithm { get { return "http://www.w3.org/2001/10/xml-exc-c14n#"; }}
public override string DefaultDigestAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#sha1"; }}
public override string DefaultEncryptionAlgorithm { get { return "http://www.w3.org/2001/04/xmlenc#aes256-cbc"; }}
public override int DefaultEncryptionKeyDerivationLength { get { return SecurityAlgorithmSuite.Default.DefaultEncryptionKeyDerivationLength; }}
public override int DefaultSignatureKeyDerivationLength { get { return SecurityAlgorithmSuite.Default.DefaultSignatureKeyDerivationLength; }}
public override int DefaultSymmetricKeyLength { get { return SecurityAlgorithmSuite.Default.DefaultSymmetricKeyLength; }}
public override string DefaultSymmetricKeyWrapAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
public override string DefaultSymmetricSignatureAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
public override bool IsAsymmetricKeyLengthSupported(int length) { return true; }
public override bool IsSymmetricKeyLengthSupported(int length) { return true; }
}
class Program
{
static void Main()
{
X509SecurityTokenParameters x509Params = new X509SecurityTokenParameters()
{
X509ReferenceStyle = X509KeyIdentifierClauseType.RawDataKeyIdentifier,
InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient,
ReferenceStyle = SecurityTokenReferenceStyle.External,
RequireDerivedKeys = false
};
SecurityBindingElement security = new TransportSecurityBindingElement()
{
MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
DefaultAlgorithmSuite = new CustomAlgorithmSuite()
};
security.EndpointSupportingTokenParameters.Endorsing.Add(x509Params);
security.SetKeyDerivation(false);
//security.IncludeTimestamp = false;
TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
//transport.RequireClientCertificate = true;
CustomBinding customBinding = new CustomBinding(security, encoding, transport);
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
var twoCertificatesInOneFile = new X509Certificate2Collection();
twoCertificatesInOneFile.Import("foo path", "foo cert pass", X509KeyStorageFlags.Exportable);
someGeneratedServiceClass client = new someGeneratedServiceClass(customBinding, new EndpointAddress(new Uri("foo webservice address"), EndpointIdentity.CreateDnsIdentity(twoCertificatesInOneFile[0].FriendlyName)));
client.ClientCredentials.ServiceCertificate.DefaultCertificate = twoCertificatesInOneFile[0];
client.ClientCredentials.ClientCertificate.Certificate = twoCertificatesInOneFile[1];
//client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
client.ClientCredentials.UserName.UserName = "foo user";
client.ClientCredentials.UserName.Password = "foo pass";
client.someServiceCall("foo", "foo", false, out i1, out i2);
}
}
I ended up using InclusionMode = SecurityTokenInclusionMode.Never, then hijacked the message and replaced incorrect tags manually.
public class CustomProxy_portClient : GeneratedProxy_portClient
{
public CustomProxy_portClient() : base()
{
Endpoint.Behaviors.Remove(typeof(ClientCredentials));
Endpoint.Behaviors.Add(new CustomClientCredentials());
}
}
class CustomClientCredentials : ClientCredentials
{
public CustomClientCredentials() : base() { }
public CustomClientCredentials(ClientCredentials ClientCredentials) : base(ClientCredentials) { }
public override SecurityTokenManager CreateSecurityTokenManager()
{
return new CustomSecurityTokenManager(this);
}
protected override ClientCredentials CloneCore()
{
return new CustomClientCredentials(this);
}
}
class CustomSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
public CustomSecurityTokenManager(ClientCredentials clientCredentials) : base(clientCredentials) { }
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CustomWSSecurityTokenSerializer();
}
}
class CustomWSSecurityTokenSerializer : WSSecurityTokenSerializer
{
protected override void WriteKeyIdentifierClauseCore(XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause)
{
string xml;
using(MemoryStream ms = new MemoryStream())
{
XmlTextWriter tempWriter = new XmlTextWriter(ms, new UTF8Encoding(false));
base.WriteKeyIdentifierClauseCore(tempWriter, keyIdentifierClause);
xml = Encoding.UTF8.GetString(ms.ToArray());
}
XmlDocument originalKeyIdentifierClause = new XmlDocument();
originalKeyIdentifierClause.LoadXml(xml);
writer.WriteStartElement("SecurityTokenReference");
writer.WriteElementString("KeyIdentifier", originalKeyIdentifierClause.InnerText);
writer.WriteEndElement();
}
}

JMockit: Mocking all implementations of an interface

Is it possible to mock all implementations of an interface?
I want to mock the WatchService interface like the following
public class ServiceTest {
#Test
public void callTest(
#Capturing
#Injectable
final WatchService ws
) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
new MockUp<ServiceTest>() {
#Mock(invocations = 1)
public void onChange() {
latch.countDown();
}
};
new NonStrictExpectations() {
{
ws.take();
result = new Delegate() {
WatchKey take(Invocation inv) {
System.out.println("> " + inv.getInvokedInstance());
try {
new File("target/newFile").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return inv.proceed();
}
};
}
};
final Thread thread = new Thread() {
#Override
public void run() {
final Path target = Paths.get("target");
final FileSystem fs = target.getFileSystem();
try {
try (WatchService watcher = fs.newWatchService()) {
target.register(watcher, ENTRY_CREATE);
while (!Thread.currentThread().isInterrupted()) {
WatchKey take = watcher.take();
onChange();
System.out.println("take " + take);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
assertTrue("", latch.await(5, TimeUnit.SECONDS));
thread.interrupt();
}
private void onChange() {
System.out.println("CHANGE");
}
How can I accomplish that?
You can use the #Capturing annotation on a mock field or mock parameter of the interface type. Below we have a complete example test (minus imports).
public class CapturingAndProceedingTest {
static class WatchKey { String key; WatchKey(String k) {key = k;} }
public interface WatchService { public abstract WatchKey take(); }
static class WatchServiceImpl1 implements WatchService {
#Override public WatchKey take() { return new WatchKey("Abc"); }
}
static class WatchServiceImpl2 implements WatchService {
#Override public WatchKey take() { return new WatchKey("123"); }
}
#Test
public void mockAllImplementationsOfAnInterface(
#Capturing // so that all implementing classes are mocked
#Injectable // so that Invocation#proceed() is supported
final WatchService watchService
) {
final List<WatchService> services = new ArrayList<>();
// Record an expectation that will match all calls to
// WatchService#take(), on any class implementing the interface.
new NonStrictExpectations() {{
watchService.take();
result = new Delegate() {
WatchKey take(Invocation inv) throws IOException {
// Do something here...
WatchService service = inv.getInvokedInstance();
services.add(service);
// ...then proceed to the real implementation.
return inv.proceed();
}
};
}};
// Instantiate and use different implementations of the interface.
WatchServiceImpl1 impl1 = new WatchServiceImpl1();
assertEquals("Abc", impl1.take().key);
WatchServiceImpl2 impl2 = new WatchServiceImpl2();
assertEquals("123", impl2.take().key);
assertEquals(Arrays.asList(impl1, impl2), services);
System.out.println(services);
}
}
See the JMockit Tutorial for more examples.

Why is my programatically added FaultContract not recognized?

I try to have my WCF services always throw detailed faults, even when not throwing them explicitly. To achieve it, I implemented:
an ErrorHandler, whose IErrorHandler.ProvideFault wraps the non-fault error as FaultException
a ServiceBehavior extension, attaching this handler AND adding to each operation a fault description of this FaultException, so the client might catch it as such.
I've decorated my service with the error handler attribute (originally I had two distinct implementations of IServiceBehavior, for the ErrorHandler and for the Operation.Faults).
I also made sure the data set into the new FaultDescription is identical to the one I inspected when defining the FaultContract on my contract.
No matter what I try, when using the FaultContract as attribute on my contract, the fault is being properly caught by the client, but when having it attached at runtime through the ApplyDispatchBehavior, only a general FaultException is being caught. Apparently, everything else (error wrapping and throwing) is working, only the addition of a FaultContract to each action at runtime fails.
Please help...
here's the code:
ErrorHandling.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using Shared.Contracts.Faults;
namespace Server.WcfExtensions
{
public class MyErrorHandler : IErrorHandler
{
#region IErrorHandler Members
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is FaultException) return;
if (!error.GetType().IsSerializable) return;
FaultException<GeneralServerFault> faultExc = new FaultException<GeneralServerFault>(new GeneralServerFault(error), new FaultReason("Server Level Error"));
MessageFault messageFault = faultExc.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, faultExc.Action);
}
#endregion
}
class ErrorHandler : Attribute, IServiceBehavior
{
Type M_ErrorHandlerType;
public Type ErrorHandlerType
{
get { return M_ErrorHandlerType; }
set { M_ErrorHandlerType = value; }
}
#region IServiceBehavior Members
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler;
try
{
errorHandler = (IErrorHandler)Activator.CreateInstance(ErrorHandlerType);
}
catch (MissingMethodException e)
{
throw new ArgumentException("Must have a public empty constructor.", e);
}
catch (InvalidCastException e)
{
throw new ArgumentException("Must implement IErrorHandler.", e);
}
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
foreach (ServiceEndpoint ep in serviceDescription.Endpoints)
{
foreach (OperationDescription opDesc in ep.Contract.Operations)
{
Type t = typeof(GeneralServerFault);
string name = t.Name;
FaultDescription faultDescription = new FaultDescription(ep.Contract.Namespace + "/" + ep.Contract.Name + "/" + opDesc.Name + name + "Fault");
faultDescription.Name = name + "Fault";
faultDescription.Namespace = ep.Contract.Namespace;
faultDescription.DetailType = t;
opDesc.Faults.Add(faultDescription);
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
#endregion
}
}
GeneralServerFault.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace Shared.Contracts.Faults
{
[DataContract] //[Serializable]
public class GeneralServerFault
{
[DataMember]
public SerializableException Wrapped
{
get;
private set;
}
public GeneralServerFault()
: base()
{
Wrapped = new SerializableException();
}
public GeneralServerFault(Exception toWrap)
: base()
{
Wrapped = new SerializableException(toWrap);
}
}
[Serializable]
public class SerializableException
{
public string Type { get; set; }
public DateTime TimeStamp { get; set; }
public string Message { get; set; }
public string StackTrace { get; set; }
public SerializableException()
{
this.TimeStamp = DateTime.Now;
}
public SerializableException(string Message)
: this()
{
this.Message = Message;
}
public SerializableException(System.Exception ex)
: this(ex.Message)
{
if (ex == null) return;
Type = ex.GetType().ToString();
this.StackTrace = ex.StackTrace;
}
public override string ToString()
{
return this.Type + " " + this.Message + this.StackTrace;
}
}
}
IContractService.cs
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.ServiceModel;
using Shared.Contracts.Faults;
namespace Shared
{
internal static class Namespaces
{
internal static class Contracts
{
public const string ServiceContracts = "http://mycompany/services";
}
}
[ServiceContract(Namespace = Namespaces.Contracts.ServiceContracts, SessionMode = SessionMode.Required)]
public interface IContactServices
{
[OperationContract]
[FaultContract(typeof(DataNotFoundFault))]
//[FaultContract(typeof(GeneralServerFault))]
void DoSomething();
}
}
ContractService.cs
using System;
using System.Collections.Generic;
using System.ServiceModel;
using Shared;
using Shared.Contracts.Faults;
using Server.WcfExtensions;
namespace Server.Services
{
[ErrorHandler(ErrorHandlerType = typeof(MyErrorHandler))]
public class ContactSevices : IContactServices
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public void DoSomething()
{
throw new InvalidCastException("bla");
}
}
}
I omitted the code of client and host

Add coded control to UIMap (Coded UI Test)

I would like to add a handwritten coded control to my UIMap.cs (not UIMap.Designer.cs).
For example, when I record: writing in a texBox, I get the following code in UIMap.Designer.cs:
public class Recorded_Writing_In_forRecordParams
{
public string UIForRecordEditText = "forRecord";
}
public class UIMainWindowWindow : WpfWindow
{
public UIMainWindowWindow()
{
this.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
this.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
this.WindowTitles.Add("MainWindow");
}
public WpfEdit UIForRecordEdit
{
get
{
if ((this.mUIForRecordEdit == null))
{
this.mUIForRecordEdit = new WpfEdit(this);
this.mUIForRecordEdit.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forRecord";
this.mUIForRecordEdit.WindowTitles.Add("MainWindow");
}
return this.mUIForRecordEdit;
}
}
private WpfEdit mUIForRecordEdit;
}
I want use this control in my CodedUITest. Is there a way to search the TextBox in the UIMap.cs by own coded or to search it in my TestMethod? Which is the best way?
Thanks for the answer, but I solved my problem on my own with the following way:
UIMap.cs
public partial class TestLittleAppUIMap
{
private MyWindow mMyWindow;
public MyWindow MMyWindow
{
get
{
if (this.mMyWindow == null)
{
this.mMyWindow = new MyWindow();
}
return this.mMyWindow;
}
}
}
public class MyWindow : WpfWindow
{
private WpfEdit mWpfEdit;
public MyWindow()
{
this.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
this.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
this.WindowTitles.Add("MainWindow");
}
public WpfEdit MWpfEdit
{
get
{
if ((this.mWpfEdit == null))
{
this.mWpfEdit = new WpfEdit(this);
#region Search Criteria
this.mWpfEdit.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forOwn";
this.mWpfEdit.WindowTitles.Add("MainWindow");
#endregion
}
return this.mWpfEdit;
}
}
CodedUI Test
[TestMethod]
public void TestLittleAppOwnMap()
{
this.UIMap.MMyWindow.MWpfEdit.DrawHighlight();
Playback.Wait(2500);
}
It is almost a copy of the designer class.
For searching directly in the TestMethod you can go like this:
[TestMethod]
public void TestLittleAppOwn()
{
WpfWindow w = new WpfWindow();
w.SearchProperties[WpfWindow.PropertyNames.Name] = "MainWindow";
w.SearchProperties.Add(new PropertyExpression(WpfWindow.PropertyNames.ClassName, "HwndWrapper", PropertyExpressionOperator.Contains));
w.DrawHighlight();
WpfEdit e = new WpfEdit(w);
e.SearchProperties[WpfEdit.PropertyNames.AutomationId] = "forOwn";
e.SetProperty("Text","myText");
e.DrawHighlight();
Playback.Wait(2500);
}
Where Playback.Wait just wait a short time for showing the Highlight.

Mock with Rhino mock -MVVM

I am using Rhino mock for mocking in my test methods. Could someone please see the TODO part in the test method and help me to mock it?
This is my service interface:
public interface ICustomersServiceAgent
{
void GetCustomers(EventHandler<GetCustomersCompletedEventArgs> callback);
void SaveCustomer(POC.Model.Customer cust, EventHandler<SaveCustomerCompletedEventArgs> callback);
}
This is my ViewModel
public class CustomerVM : ViewModelBase
{
private Model.Customer _curentCustomer;
private RelayCommand _saveCommand;
private ICustomersServiceAgent ServiceAgent { get; set; }
private bool isSaved;
private RelayCommand _calculateAgeCommand;
private Decimal age;
private DateTime dateOfBirth;
public CustomerVM(ICustomersServiceAgent serviceAgent)
{
if (serviceAgent == null)
{
ServiceAgent = ServiceManager.GetCustomerServiceManagement();
}
else
{
ServiceAgent =serviceAgent;
}
WireCommands();
}
// if curent object is null then it should be intialize
public Model.Customer CurentCustomer
{
get { return _curentCustomer ?? (_curentCustomer = new Model.Customer()); }
set
{
if (_curentCustomer != value)
{
_curentCustomer = value;
OnPropertyChanged("CurentCustomer");
}
}
}
public RelayCommand CalculateAgeCommand
{
get;
private set;
}
private void WireCommands()
{
SaveCustomerCommand = new RelayCommand(SaveCustomer);
SaveCustomerCommand.IsEnabled = true;
CalculateAgeCommand = new RelayCommand(CalculateAge);
}
private void SaveCustomer()
{
var cus = CurentCustomer;
ServiceAgent.SaveCustomer(cus, (s, e) =>
{
IsSaved = e.Result;
});
}
private void CalculateAge()
{
Age = DateTime.Now.Year - DateOfBirth.Year;
}
public RelayCommand SaveCustomerCommand
{
get;
private set;
}
public bool IsSaved
{
get { return isSaved; }
set
{
isSaved = value;
OnPropertyChanged("IsSaved");
}
}
public decimal Age
{
get { return age; }
set {
age = value;
OnPropertyChanged("Age");
}
}
public DateTime DateOfBirth
{
get { return dateOfBirth; }
set {
dateOfBirth = value;
OnPropertyChanged("DateOfBirth");
}
}
}
I want to test the SaveCustomerCommand in ViewModel above.
So In the my test method, I want to mock the void SaveCustomer(POC.Model.Customer cust, EventHandler<SaveCustomerCompletedEventArgs> callback) method in the ICustomersServiceAgent interface.
This is my test method, see the ToDo part
[TestMethod]
public void SaveCustomerCommandTest()
{
var customerServiceMock = MockRepository.GenerateMock<ICustomersServiceAgent>();
var customerVM = new POC.SilverlightClient.ViewModel.CustomerVM(customerServiceMock);
// TO do : Code to mock SaveCustomer method ///////////////////////////////////
var saveCustomerCommand = customerVM.SaveCustomerCommand;
saveCustomerCommand.Execute(null);
Assert.IsTrue(customerVM.IsSaved);
}
Could someone please explain how I can do this?
I don't see why you need to mock SaveCustomer. All the private SaveCustomer method does is invoke the ServiceAgent service which you already are mocking. I assume the RelayCommand class invokes the delegate you're sending in the constructor parameter which is the call to SaveCustomer. Have you tried running the unit test in your question as-is?
Try following:
customerServiceMock.Stub(sa => sa.SaveCustomer(Arg<POC.Model.Customer>.Is.Anything, Arg<EventHandler<SaveCustomerCompletedEventArgs>>.Is.Anything)).WhenCalled(invocation =>
{
((EventHandler<SaveCustomerCompletedEventArgs>)invocation.Arguments[1])(
customerServiceMock,
new SaveCustomerCompletedEventArgs { Result = true });
});