Monthly Archives: March 2015

Coded UI Test – Recording mouse clicks

Coded UI Tests are something I’ve always thought would be useful, but have only recently actually used. This post is details of the first issue that I came up against.

The Problem

When you record a Coded UI test, you tell VS you want to do so, run whatever application that you want to test, and then record a series of tests; usually this means clicking the screen. Here’s what one of the UI projects looks like after you finish recording:

CodedUIStructure

The designer file looks something like this for a series of clicks:

        public void RunBuildAnalysisAndClose()
        {
            #region Variable Declarations
            WpfButton uIValidateURIButton = this.UIWpfWindow.UIValidateURIButton;
            WpfButton uIBuildAnalysisButton = this.UIWpfWindow.UIBuildAnalysisButton;
            WinButton uICloseButton = this.UIBuildAnalysisWindow1.UICloseButton;
            WinButton uICloseButton1 = this.UIItemWindow.UICloseButton;
            #endregion

            // Click 'Validate URI' button
            Mouse.Click(uIValidateURIButton, new Point(677, 6));

            // Click 'Build Analysis' button
            Mouse.Click(uIBuildAnalysisButton, new Point(619, 9));

            // Click 'Close' button
            Mouse.Click(uICloseButton, new Point(16, 5));

            // Click 'Close' button
            Mouse.Click(uICloseButton1, new Point(30, 9));
        }

The recording that generated this was a quick test of a codeplex project of mine called TFS Utils.

My initial thought about this was: what happens when the buttons move around the screen, or the resolution changes. So I tried both of those things… and it still works. The points above are relative; what’s more: they are optional. The following is the same code, copied over to UIMap.cs and the points removed.

        public void RunBuildAnalysisAndCloseManual()
        {
            #region Variable Declarations
            WpfButton uIValidateURIButton = this.UIWpfWindow.UIValidateURIButton;
            WpfButton uIBuildAnalysisButton = this.UIWpfWindow.UIBuildAnalysisButton;
            WinButton uICloseButton = this.UIBuildAnalysisWindow1.UICloseButton;
            WinButton uICloseButton1 = this.UIItemWindow.UICloseButton;
            #endregion

            // Click 'Validate URI' button
            Mouse.Click(uIValidateURIButton);

            // Click 'Build Analysis' button
            Mouse.Click(uIBuildAnalysisButton);

            // Click 'Close' button
            Mouse.Click(uICloseButton);

            // Click 'Close' button
            Mouse.Click(uICloseButton1);
        }

Quick Point on the Points

Since this Point seemed effectively pointless, I had a look around, and it turns out there is a reason; which is for menu buttons, where you need to specify a particular point within the button; rather than just anywhere. I would argue that the default recording should be what’s above, as it seems cleaner. I’m not strictly sure who I would argue that with though.

Disabled Controls

If you look at the menu in the project referenced, you’ll see that the menu items enable only when the URI is validated. This took me a while to work out; because if it’s not available, it just breaks the test:

        public void RunBuildAnalysisAndCloseManual()
        {
            #region Variable Declarations
            WpfButton uIValidateURIButton = this.UIWpfWindow.UIValidateURIButton;
            WpfButton uIBuildAnalysisButton = this.UIWpfWindow.UIBuildAnalysisButton;
            WinButton uICloseButton = this.UIBuildAnalysisWindow1.UICloseButton;
            WinButton uICloseButton1 = this.UIItemWindow.UICloseButton;
            #endregion

            // Click 'Validate URI' button
            Mouse.Click(uIValidateURIButton);

            // Wait as long as 30 seconds for this control to become enabled
            uIBuildAnalysisButton.WaitForControlEnabled(30000);

            // Click 'Build Analysis' button
            Mouse.Click(uIBuildAnalysisButton);
            
            // Click 'Close' button
            Mouse.Click(uICloseButton);

            // Click 'Close' button
            Mouse.Click(uICloseButton1);
        }

It’s not difficult to see how this could be extracted into a helper method:

        private void ClickButton(WpfButton button)
        {
            button.WaitForControlEnabled(30000);                        
            Mouse.Click(button);
        }

Conclusion

From the above investigation, I’ve come to a few conclusions:
1. Don’t rely on the designer file (and don’t bother changing it, as it’s generated code)
2. Hand roll tests – you get far more control

Toshiba Touch Pad Stops Responding

Admittedly this isn’t my usual type of post. However, I’ve had a number of occasions where the touchpad on my Toshiba Satellite L855-188 has stopped responding.

When I say that it doesn’t respond, it actually behaves in a bazaar way: the mouse acts as though the machine were incredibly busy (an occasional jerky movement every few minutes – yes minutes). However, if you hold a mouse button down, it works fine (that is, the mouse responds correctly – obviously trying to navigate Windows with a mouse button constantly pressed presents its own problems).

The Solution

Launch Task Manager and kill the process “Synaptics TouchPad 64-bit Enhancements”:

TaskManagerToshibaTouchpad

And it’s back to normal!

However

Even though this worked, it happened the next time I restarted the computer. The final fix is in the Task Scheduler:

TaskScheduler

Just disable the task in the task scheduler library.

Unable to get IBuildServer – always returning null

I recently had a very strange error while using the TFS API. The error was with the following code:

var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(URI));
var vcs = tfs.GetService<VersionControlServer>();
var buildServer = tfs.GetService<IBuildServer>();                

The problem being that `buildServer` was being set to null. I had the TFS server set-up locally, and there was a controller, an agent and a build configured.

I spent a good while trying to debug, what I thought was, an error with the code.

The Solution

Turns out the problem was with the reference:

TFSBuildRef

The problem was that I was referencing the wrong version (trying to connect to TFS2013 but the build client version was 11.0.0.0). Swapping it to version 12.0.0.0 works fine.

It sounds like a silly mistake, but if you make it, it’s very difficult to spot.

MVVM Cross – Stubbing out IMvxMainThreadDispatcher with RhinoMocks

This article describes how to stub out the IMvxMainThreadDispatcher, used by MVVM Cross, using Rhino Mocks.

Here is an excellent article on unit testing in MVVM Cross.

In it, Stuart Lodge describes a manual mock to replace the `IMvxMainThreadDispatcher`. I’ve recently started using RhinoMocks again, and the following is basically the manual mock described in the above article, in RhinoMocks:

var mainThreadDispatcher = MockRepository.GenerateMock<IMvxMainThreadDispatcher>();
mainThreadDispatcher.Stub(x => x.RequestMainThreadAction(Arg<Action>.Is.Anything)).WhenCalled(a => ((Action)a.Arguments.First())()).Return(true);
Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(mainThreadDispatcher);            

As with many of my posts, this is predominantly for my own use; and, as with those other posts, I hope you’ll find this useful.

MVVM Light CanExecute Command – Re-evaluate en-mass

MVVM Light CanExecute doesn’t work for commands

The following code in MVVM light does not work:

RelayCommand newCommand = new RelayCommand(onExecute, canExecute);

. . . 

canExecute = true;

. . .

canExecute = false;

That is, the bound command will not update. Even if the changed `canExecute` raises property changed.

Raise it manually

So, the way to fix this is as follows:

        public bool canExecute
        {
            get { return _canExecute; }
            set
            {
                _canExecute = value;
                RaisePropertyChanged();
                newCommand.RaiseCanExecuteChanged();
            }
        }

Which works fine. However, what if you have 10 commands, and they all have the same dependant property?

Real life

Here’s my method of working around this. Is it effectively a `RaiseAllPropertyChanged()` for commands. Start with a class level list of commands:

        // Store a local list of all registered commands to inform of updates
        private List<RelayCommand> _registeredCommands;

Now create a function that allows us to iterate this and call RaiseCanExecuteChanged to all of them:

        private void ReevaluateCommands()
        {
            foreach (var eachCommand in _registeredCommands)
            {
                eachCommand.RaiseCanExecuteChanged();
            }

        }

Finally, we can simply call this when the dependant property changes:

        public bool canExecute
        {
            get { return _canExecute; }
            set
            {
                _canExecute = value;
                RaisePropertyChanged();
                ReevaluateCommands();
            }
        }

Magic.

Disclaimer

I kind of stole the idea for this from here. I’m not selling this as a massively scalable, all singing, all dancing solution. It just works for my particular scenario, which is here:

TFS Utilities

Playing Media in Windows Universal Apps

I recently had cause to write a universal app that has voice capabilities. Hopefully it will shortly be available on the Windows Store.

Adding voice synthesis, while a seemingly basic task, proved to be anything but. What follows is a series of trials and tribulations that I have overcome in order to bring this app to the public!

The Code

Here’s the basic code to get started.

                var voiceStream = await synth.SynthesizeTextToStreamAsync("Hello");
                
                MediaElement mediaElement = new MediaElement();

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.AutoPlay = false;
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                mediaElement.Play();

Windows Phone

The first issue I encountered with Windows Phone was the volume. Having maxed out my laptop speakers, I managed get a faint whimper. What I finally deduced is that, for some reason, when the emulator starts, it starts at half volume. To increase it you have to press the phone’s volume buttons (which I initially assumed were just there for aesthetics. Clearly Microsoft haven’t entirely abandoned skeuomorphism.

Phone

The volume controls are the top right buttons (which I happened to know because I have owned a Windows Phone in the past). Once you press it then a more sensible interface appears and you can change either the ringer volume, or the game volume.

Overtalking

Although the code above does work, try calling the code in a loop (or just twice). What happens is that it doesn’t wait for itself to finish.

What I didn’t realise (until I asked this) was that there are some events which supposedly fire when the media element has finished playing.

                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
                
                MediaElement mediaElement = new MediaElement();

                mediaElement.Loaded += mediaElement_Loaded;
                mediaElement.MediaEnded += mediaElement_MediaEnded;
                mediaElement.MediaFailed += mediaElement_MediaFailed;

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.AutoPlay = false;
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;
                
                mediaElement.Play();

I say supposedly, because when I first tried to capture the events, they did nothing. After a bit of searching, it turns out that the element needs to be part of the visual tree! Which of course makes total sense – an AUDIO media element must be part of the VISUAL tree.

In the Visual Tree

The code below now looks for the media element in the visual tree, and if it can’t find one, adds it. It also uses the TaskCompletionSource object to await the audio stream.

            using (SpeechSynthesizer synth = new SpeechSynthesizer())
            {
                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);
                
                MediaElement mediaElement;
                
                mediaElement = this.rootControl.Children.FirstOrDefault(m => (m as MediaElement) != null) as MediaElement;
                if (mediaElement == null)
                {
                    mediaElement = new MediaElement();
                    this.rootControl.Children.Add(mediaElement);
                }
                
                mediaElement.SetSource(voiceStream, voiceStream.ContentType);                
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                var tcs = new TaskCompletionSource<bool>();
                mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };
                mediaElement.Play();

                await tcs.Task;
                
            }

That works. At least, it works on Windows Phone. Because it uses a media element, I thought putting it on a shared XAML page would work… but it doesn’t. Windows 8.1 just sits there quietly and says nothing.

Windows Store

After much trial and error, it occurred to me (prompted by a comment on the above question) that if the problem was down to a deadlock, then destroying and recreating the control might clear this up.

Amazingly, that did seem to work; the working code is:

            using (SpeechSynthesizer synth = new SpeechSynthesizer())
            {
                var voiceStream = await synth.SynthesizeTextToStreamAsync(toSay);

                MediaElement mediaElement;

                mediaElement = rootControl.Children.FirstOrDefault(a => a as MediaElement != null) as MediaElement;
                if (mediaElement == null)
                {
                    mediaElement = new MediaElement();
                    
                    rootControl.Children.Add(mediaElement);
                }

                mediaElement.SetSource(voiceStream, voiceStream.ContentType);
                mediaElement.Volume = 1;
                mediaElement.IsMuted = false;

                var tcs = new TaskCompletionSource<bool>();                
                mediaElement.MediaEnded += (o, e) => { tcs.TrySetResult(true); };               

                mediaElement.Play();                

                await tcs.Task;

                rootControl.Children.Remove(mediaElement);

            }

And this does seem to work on both platforms.