How to test a MessageBox in wpf? - wpf

I'm going to do some unit tests and I am struggling with a MessageBox. I have a MessageBox that is showing a text and an "Ok" button in my code. When I trying to unit test the method that contains the MessageBox.Show("Text"), it pops up in the unit test, too, and I have to click "Ok" before it can pass through, which is a bad.
Does anyone know how to go around it? I think I need some kind of code that fakes this MessageBox and clicking "Ok", but I dont know how to do this. I'm a junior programmer, so please explain it as easy as you can ;) and gladly with some code examples.
This is my code for the MessageBox:
public void GetPopUpWithErrorMessage()
{
MessageBox.Show("Error Message", "text",
MessageBoxButton.OK);
}
Edit
I just realised that Fluent Assertions is used in the project. Does anyone know how to implement that in the test code? is it the same way as #thatguy showed?

You have to create a service that implements an interface that you can mock in your tests.
public interface IMessageBoxService
{
void ShowMessageBox(string title, string message);
}
public class MessageBoxService : IMessageBoxService
{
public void ShowMessageBox(string title, string message)
{
MessageBox.Show(message, title, MessageBoxButton.OK);
}
}
In the class where you use it, you would pass this service by its interface, e.g. in the constructor, so the class only knows its contract, but not its implementation.
public class MyClass
{
private IMessageBoxService _messageBoxService;
public MyClass(IMessageBoxService messageBoxService)
{
_messageBoxService = messageBoxService;
}
public void GetPopUpWithErrorMessage()
{
_messageBoxService.ShowMessageBox("text", "Error Message");
}
}
In the test class, you need to use a mocking framework like Moq that creates a mock object from an interface, which is just a stub that you can use to inject the behavior for any method or property that you use in your test.
In this example using NUnit and Moq, messageBoxService is created as a mock object that implements the IMessageBoxService interface. All methods do nothing unless you specify what they should do or return via Setup, but that is another topic. The last line shows how you could check if a sepcific method on the mock was invoked during the test.
[TestFixture]
public class MyClassTest
{
[Test]
public void MyTest()
{
var messageBoxService = Mock.Of<IMessageBoxService>();
var myClass = new MyClass(messageBoxService);
// ...your test code.
// Checks if the "ShowMessageBox" method in the service was called with any strings
Mock.Get(messageBoxService).Verify(mock => mock.ShowMessageBox(It.IsAny<string>(), It.IsAny<string>()));
}
}
Creating a service and an interface is not just useful for mocking, but also for separating view and logic, as you can extract the calling of a message box to a service which has an implementation hidden behind an interface. Moreover you can easily implement dependency injection via constructors.

Related

Elegant way to handle exceptions in Test cases of MVVM Light's ViewModel

I am working on a wpf application using mvvm light toolkit. Whenever something goes outside the business logic we'll prompt the user with the message box and I send the message from view model to view using
Messenger.Default.Send(Token,"Some text message here");
Now I am writing test cases for view models and in some cases, Code Under Test is linked with such message calls. These are exceptions to me but test cases does not treat them exception as long as it is not being called by throw exception("message")
Suggestions.
Assuming you are sending message from VM to View, which handles the actual "showing logic", then just register for the message in your VM tests and verify that it has been sent/received. For example:
[TestMethod]
public void SendSomethingBadHappenedMessageTest()
{
const string expected = "oh noes!";
string actual = null;
// Register for message to ensure message was sent from VM
Messenger.Default.Register<SomethingBadHappenedMessage>(this,
message => actual = message.Message);
// Assuming command triggers Messenger.Send
_viewModel.SomethingBadHappenedCommand.Execute(expected);
Assert.AreEqual(expected, actual);
}
If you test for exceptions, just mark test method with ExpectedException attribute.
I assume you are trying to verify that the business logic detects a problem and the correct message box is being "shown" in your test case. If that's so, here's what I do:
Instead of using messaging, create a UserNotificationService and IUserNotificationService interface. The concrete implementation would be something like:
public class UserNotificationService : IUserNotificationService
{
public void MessageBox(string message)
{
// code to make the message box pop up goes here
}
}
Inject IUserNotificationService in your view model's constructor (you already have SimpleIoC since you are using mvvm-light) and use it to communicate with the user.
When unit testing, either mock the IUserNotificationService or create a new FakeUserNotificationService class that is capable of verifying the correct message/error was sent. Put that in the constructor of the view model being tested.
public class FakeUserNotificationService : IUserNotificationService
{
public void MessageBox(string message)
{
LastMessage = message;
}
public string LastMessage {get; set;}
}
In your test:
var ns = new FakeUserNotificationService();
var viewModel = new MyViewModel(ns);
viewModel.DoSomethingBad();
Assert.AreEqual(ns.LastMessage, "expected error message");

How to share data resources between widgets in GWT

I am using GWT and AppEngine for a project. I would like to know how can I share data (ArrayList objects)between widgets, so I could centralize the logic and reduce the number of RPC calls to the server.
I have thought of two ways, but I don't know which is better:
1) When I instantiate the widget, I pass the ArrayList object as a parameter, although I don't know how to do that because the widget gets instantiated with :
ThisAppShell shell = GWT.create(ThisAppShell.class);
2) By using a mechanism like eventBus
http://www.dev-articles.com/article/Gwt-EventBus-(HandlerManager)-the-easy-way-396001
When the user loads the application,after the login process is complete, I would like to download a list of employees which should be available for all widgets. This should all be done in the onModuleLoad() method. I would like to download them all at startup because I would like to implement some sort of caching mechanism. For example, I want to have 2 ArrayList instances:
- emplListOnStart which is populated when the application is loading
- emplListChanges, an array on which the user will make modifications from inside widgets.
After the user has finished making the changes (he presses the "Save" button), the two arrays will be compared, the differences will be saved in appengine (via RPC) and also updated in emplListOnStart.
This is the code for the EntryPoint class:
public class ThisApp implements EntryPoint {
ThisAppShell shell = GWT.create(ThisAppShell.class);
LoginServiceAsync loginService = GWT.create(LoginService.class);
private ArrayList<Employee> emplListOnStart;
private ArrayList<Employee> emplListChanges;
public void onModuleLoad() {
RootLayoutPanel.get().clear();
RootLayoutPanel.get().add(shell);
loginService.isAuthenticated(new AsyncCallback<UserDto>() {
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
public void onSuccess(UserDto result) {
//Here I should load the emplListOnStart list;
}
});
shell.getLogoutLink().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
loginService.logout(new AsyncCallback() {
public void onFailure(Throwable caught) {
}
public void onSuccess(Object result) {
//Here the user will get logged out
}
});
Window.Location.assign("");
}
});
}
}
And here is the code for the widget:
public class ThisAppShell extends Composite {
private static ThisAppShellUiBinder uiBinder = GWT
.create(ThisAppShellUiBinder.class);
interface ThisAppShellUiBinder extends UiBinder<Widget, ThisAppShell> {
}
#UiField
Anchor logout_link;
#UiField
StackLayoutPanel stackLPanel;
#UiField
TabLayoutPanel tabLPanel;
public ThisAppShell() {
initWidget(uiBinder.createAndBindUi(this));
initializeWidget();
}
public void initializeWidget() {
stackLPanel.add(new HTML("Manage empl."), new HTML("Employees"), 30);
stackLPanel.add(new HTML("Manage Dept."), new HTML("Departments"), 30);
// Add a home tab
HTML homeText = new HTML("This is the home tab");
tabLPanel.add(homeText, "Home");
// Add a tab
HTML moreInfo = new HTML("This is the more info tab");
tabLPanel.add(moreInfo, "More info");
// Return the content
tabLPanel.selectTab(0);
}
public Anchor getLogoutLink() {
return logout_link;
}
}
Is this possible, or how could this be done better?
Thank you.
I think there are two ways to do it:
Create a setter on your widget to set your ArrayList instances (setData()). You can then call this function in the onSuccess method of your loginService.
Inject the singleton instance of a global EventBus into your widget (using i.e. gin/guice) and fire an event containing your data. In the widget you have to attach an EventHandler for the specific event (i.e. LoadEmplListEvent).
I think both solutions are fine to use.
Solution one creates a tighter coupling to your widget but is easier to implement and I think you should take this route if you only have a small number of widgets where you work
with the data.
Solution is a cleaner approach because it de-couples your widgets from the rest. You fire the event the data in your onSuccess method once and you don't care about the widgets.
The widgets that are interested in the data will make sure that they handle the event appropriately (by handling the event). I guess if you have a lot of widgets that have to deal with the data the second approach is the one to go for.

Rhino mocks unit test method args

I am new to rhino mocks and unit testing in general. I am starting to write some tests for my wpf mvvm app. Here is a sample scenario I am trying to test:
The view model:
List<DataItems> _theData = new List<DataItems>();
public MyViewModel(IServer server)
{
_server = server;
InitializeData();
}
private void InitializeData()
{
_server.GetData(MyCallback);
}
private void MyCallback()
{
_theData = _server.TheData;
}
public List<DataItems> VMData
{
get
{
return _theData;
}
}
Server:
public List<DataItems> TheData
{
get
{
return _cachedData;
}
}
public void GetData(Action callBack)
{
//Populate cached data
...
if(callBack != null)
{
callBack();
}
}
In my test, I want to verify that viewModel.VMData.Count == server.TheData.Count. I tried using rhino mocks to stub the server, pre-poulating TheData with some values. The I called the view model constructor, and then tried to compare the counts.
My problem is that I do not know how to get my server to actually call back into my view model. After the vm constructor is called, InitializeData() is called as expected but the stub server's GetData call is not made.
How can I make this simple test work?
if you are stubbing IServer and expecting that the calling a method on the stub will invoke the implementation in your concrete class, that is your misconception. the GetData method on the stub instance will only return what you tell it to, and not execute any code in the concrete dependency. remember that the only thing your stub IServer object has in common with your concrete implemetation of IServer is that they both implement IServer. expecting that the side effects in the method in your concrete implemenation will happen when calling the method on the stub is just faulty.
as to how to make it work: there's not really a good way to do this test as you are stating with the design of these classes as is. you are trying to test that a side effect occurred in the dependency that you are stubbing out of participation. to really test what you want here and if you want to keep these classes with this relationship, i'd suggest that you don't mock server at all and use the real object. redesign the server so that it depends on another component that loads from the cache so you can stub that thing instead.

Unable to return collections or arrays from JAX-WS Web Service

I found that I was unable to return collections from my JAX-WS Web Service.
I appreciate that the Java Collections API may not be supported by all clients, so I switched to return an array, but I can't seem to do this either.
I've set up my web service as follows:
#WebService
public class MyClass {
public ReturnClass[] getArrayOfStuff() {
// extremely complex business logic... or not
return new ReturnClass[] {new ReturnClass(), new ReturnClass()};
}
}
And the ReturnClass is just a POJO. I created another method that returns a single instance, and that works. It just seems to be a problem when I use collections/arrays.
When I deploy the service, I get the following exception when I use it:
javax.xml.bind.MarshalException - with linked exception:
[javax.xml.bind.JAXBException: [LReturnClass; is not known to this context]
Do I need to annotate the ReturnClass class somehow to make JAX-WS aware of it?
Or have I done something else wrong?
I am unsure of wheter this is the correct way to do it, but in one case where I wanted to return a collection I wrapped the collection inside another class:
#WebService
public class MyClass {
public CollectionOfStuff getArrayOfStuff() {
return new CollectionOfStuff(new ReturnClass(), new ReturnClass());
}
}
And then:
public class CollectionOfStuff {
// Stuff here
private List<ReturnClass> = new ArrayList<ReturnClass>();
public CollectionOfStuff(ReturnClass... args) {
// ...
}
}
Disclaimer: I don't have the actual code in front of me, so I guess my example lacks some annotations or the like, but that's the gist of it.

Issue intercepting property in Silverlight application

I am using Ninject as DI container in a Silverlight application. Now I am extending the application to support interception and started integrating DynamicProxy2 extension for Ninject. I am trying to intercept call to properties on a ViewModel and ending up getting following exception:
“Attempt to access the method failed: System.Reflection.Emit.DynamicMethod..ctor(System.String, System.Type, System.Type[], System.Reflection.Module, Boolean)”
This exception is thrown when invocation.Proceed() method is called. I tried two implementations of the interceptor and they both fail
public class NotifyPropertyChangedInterceptor: SimpleInterceptor
{
protected override void AfterInvoke(IInvocation invocation)
{
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
public class NotifyPropertyChangedInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
I want to call OnPropertyChanged method on the ViewModel when property value is set.
I am using Attribute based interception.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotifyPropertyChangedAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
if(request.Method.Name.StartsWith("set_"))
return request.Context.Kernel.Get<NotifyPropertyChangedInterceptor>();
return null;
}
}
I tested the implementation with a Console Application and it works alright.
I also noted in Console Application as long as I had Ninject.Extensions.Interception.DynamicProxy2.dll in same folder as Ninject.dll I did not have to explicitly load DynamicProxy2Module into the Kernel, where as I had to explicitly load it for Silverlight application as follows:
IKernel kernel = new StandardKernel(new DIModules(), new DynamicProxy2Module());
Could someone please help? Thanks
Reflection can be really tricky in silverlight because of security issues.
Check Gabe's answer for this question, it's the same problem.
The good news is that you can achieve the same functionality you want using dynamic instead of proxies. Just extend your ViewModel from DynamicObject and override the TrySetMember method.
I hope it helps :)

Resources