<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>2018-01 on Funky Si's Test</title><link>https://blog-test.funkysi1701.com/2018/01/</link><description>Recent content in 2018-01 on Funky Si's Test</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><managingEditor>funkysi1701@gmail.com (Simon Foster)</managingEditor><webMaster>funkysi1701@gmail.com (Simon Foster)</webMaster><lastBuildDate>Mon, 29 Jan 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://blog-test.funkysi1701.com/2018/01/index.xml" rel="self" type="application/rss+xml"/><item><title>Flexible architecture and interfaces</title><link>https://blog-test.funkysi1701.com/posts/2018/flexible-architecture/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 29 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/flexible-architecture/</guid><category term="Architecture">Architecture</category><category term="Azure">Azure</category><description>&lt;p&gt;I have blogged a few times about &lt;a href="https://www.funkysi1701.com/posts/2017/interfaces/" target="_blank" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;
, and how useful they are for producing good quality maintainable code. Let’s look at a problem and the solution I came up with which I am quite proud of.&lt;/p&gt;
&lt;p&gt;As previously mentioned I am in the process of moving &lt;a href="https://www.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/" target="_blank" rel="noopener noreferrer"&gt;images&lt;/a&gt;
from AWS to Azure blob storage. Now that the actual files themselves have been moved I need to change the code that references them.&lt;/p&gt;
&lt;p&gt;Now I could find all the code that uses the AWS API and replace it with the Azure API but I am not very good at predicting the future, we may stay on Azure for a while, we may move to AWS or Google Cloud, or we may want to go back to files sitting on a server.&lt;/p&gt;
&lt;p&gt;Lets try and code a solution that is as flexible as possible. As you have probably guessed I am going to create an interface.&lt;/p&gt;
&lt;p&gt;At first I thought about creating an interface called &lt;strong&gt;ICloudStorage&lt;/strong&gt; , however this isn’t flexible enough as what happens if we go back to sticking files on a server so instead I created &lt;strong&gt;IStorage&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I created three classes that implemented IStorage, &lt;strong&gt;AWSStorage&lt;/strong&gt; , &lt;strong&gt;AzureStorage&lt;/strong&gt; and mostly for testing at the moment &lt;strong&gt;FileStorage&lt;/strong&gt;. I then created a class Storage that would call these three classes. Initially I created it like this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IStorage _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Storage(IStorage repo)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _repo = repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However this would require I call it like Storage(new AzureStorage()) and I would need to know everywhere in my code which implementation I want to use. This isn’t too bad as when we change from AWS to Azure we would need to do a find and replace throughout the code and replace all AWSStorage and make them AzureStorage.&lt;/p&gt;
&lt;p&gt;However we can do better than that.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Storage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; IStorage _repo;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; Storage()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Type obj = Type.GetType(ConfigurationManager.AppSettings[&lt;span style="color:#e6db74"&gt;&amp;#34;DefaultStorageRepository&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ConstructorInfo constructor = obj.GetConstructor(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Type[] { });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _repo = (IStorage)constructor.Invoke(&lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code will read from the web.config which implementation to use and that will decide which class to call. This means that to change from AWS to Azure we do not need to redeploy any code, all we need to do is change the web.config.&lt;/p&gt;
&lt;p&gt;Let’s look at the three lines and see if we can understand what is happening.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type.GetType()&lt;/strong&gt; looks straight forward and gets the type from the web.config&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;obj.GetConstructor()&lt;/strong&gt; This gets the constructor for the type we have just found.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;constructor.Invoke&lt;/strong&gt; This then invokes the constructor and it then gets cast to the interface so can be used by the _repo variable.&lt;/p&gt;
&lt;p&gt;This is all fairly simple and makes sense, however it has produced some very flexible code and allows the code to be extended without recompiling.&lt;/p&gt;
&lt;p&gt;Let’s look at a hypothetical example. We want to add support for Google Cloud Storage. All we need to do is create a class library which implements the IStorage interface, place the compiled binary in the website and update the web.config to reference it. I haven’t tried this hypothetical example so it might be more complex than I think but in theory it should work.&lt;/p&gt;
&lt;p&gt;I am pretty excited at how flexible this code can be, hopefully I will use code like this more often now I understand it.&lt;/p&gt;</description></item><item><title>Moving files into blob storage</title><link>https://blog-test.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/moving-blobs-cloud-suppliers/</guid><category term="DevOps">DevOps</category><category term="Azure">Azure</category><description>&lt;p&gt;We are in the process of moving our companies websites onto the Azure platform. One of the challenges was to move image files out of the website project into blob storage. This week I have moved 150,000 of them.&lt;/p&gt;
&lt;p&gt;One thing I keep banging on about is that your source code should not contain data. If it does every time you do a deployment you need to consider where these images are located and ensure you don’t overwrite or loose any. It also goes without saying that deployments of a few Mb are a lot quicker than deployments of 100s of Mb.&lt;/p&gt;
&lt;p&gt;Azure blob storage also gives you advantages like distributing storage across multiple datacenters which would be impossible with traditional files on a server.&lt;/p&gt;
&lt;p&gt;So now that we have established that this is a good idea lets look at how we could move large amounts of data. In my case all the filenames are stored in a SQL database so the plan of action was to simply loop through the files in the database, download from current storage (either locally or other cloud storage), upload to Azure and tidy up afterwards. Due to the number of images I am going to update the database and mark when a file has been processed so I can do the move over several days.&lt;/p&gt;
&lt;p&gt;This is my code&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; source = &lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com/images/&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; tmp = Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!Directory.Exists(tmp))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Directory.CreateDirectory(tmp);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; fixturePhotos = db.Images.Where(x =&amp;gt; x.Moved == &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; || x.Moved == &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;).Take(id);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;foreach&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; photo &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; fixturePhotos)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; path = getFilePath(photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (!Directory.Exists(Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt; + path)))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Directory.CreateDirectory(Server.MapPath(&lt;span style="color:#e6db74"&gt;&amp;#34;~/tmp/&amp;#34;&lt;/span&gt; + path));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WebClient WebClient = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; WebClient();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WebClient.DownloadFile(source + photo.FileName, tmp + photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; FileUploader f = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; FileUploader(tmp + photo.FileName, photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.IO.File.Delete(tmp + photo.FileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; photo.Moved = &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;catch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; photo.Moved = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;db.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (Directory.Exists(tmp))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Directory.Delete(tmp, &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First of all I create a tmp folder in the root of my website if it doesn’t exist to store my images temporarily.&lt;/p&gt;
&lt;p&gt;I then use an entity framework model to query the database that haven’t been moved, and I use the take() method to limit how many results I process. (I have been passing in 1000 at a time)&lt;/p&gt;
&lt;p&gt;I then use a foreach loop over all these files to perform the following actions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create additional subfolders if the filename variable stored in the database isn’t actually a filename but a filepath, note you will have to split filename and filepath which I haven’t included code for here.&lt;/li&gt;
&lt;li&gt;Download file from the original url and save into the temporary folder&lt;/li&gt;
&lt;li&gt;Upload to Azure&lt;/li&gt;
&lt;li&gt;Delete temporary file&lt;/li&gt;
&lt;li&gt;Update database giving a success or fail&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the foreach is finished I commit the database changes and delete the temporary folder. I am sure there must be other ways to do this transfer but this was quick and easy to setup and now I have a copy of all the files in Azure storage so I can test out other issues with my website.&lt;/p&gt;
&lt;p&gt;One last tip about how to schedule this code. I called the above code from a MVC controller and then wrote a Azure Function to call this code on a schedule.&lt;/p&gt;</description></item><item><title>Website UI Testing</title><link>https://blog-test.funkysi1701.com/posts/2018/website-ui-testing/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/website-ui-testing/</guid><category term="Testing">Testing</category><category term="Website">Website</category><category term="UI">UI</category><description>&lt;p&gt;Last week I looked at testing the &lt;a href="https://dev.to/funkysi1701/mobile-app-ui-testing-jgg-temp-slug-9433902" target="_blank" rel="noopener noreferrer"&gt;UI of mobile apps&lt;/a&gt;
, this week lets look at how we could do a similar thing for websites.&lt;/p&gt;
&lt;p&gt;Testing the user interface is not an excuse for a lack of &lt;a href="https://dev.to/funkysi1701/writing-your-first-test-53gi-temp-slug-2645725" target="_blank" rel="noopener noreferrer"&gt;unit tests&lt;/a&gt;
. Testing the user interface takes longer so for keep creating your small unit tests that can be run after ever build. That said lets look at how you create a UI test.&lt;/p&gt;
&lt;p&gt;Create a Unit Test project as normal. Now install the following nuget packages&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Selenium.WebDriver.ChromeDriverSelenium.WebDriverSelenium.WebDriver.PhantomJS.Xplatform
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I am going to be using Selenium to achieve my website testing and I am going to concentrate on the Chrome browser. However packages exist for other browsers so have a look at the following and I expect there are others as well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Selenium.WebDriver.IEDriverSelenium.Firefox.WebDriver
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://seleniumhq.org/" target="_blank" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt;
started life as a plugin for Firefox to help create automated tests, however the latest version of Firefox is not compatible with the plugin as I write this. I have not had to install any plugins or extensions to my browsers to achieve my testing.&lt;/p&gt;
&lt;p&gt;Enough talk lets write a test. First we create two instance variables to store the baseURL and the driver for the browser you are using.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; baseURL = &lt;span style="color:#e6db74"&gt;&amp;#34;https://www.example.com/&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; RemoteWebDriver driver;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next we need to set things up for the test to run. This creates an instance of the chrome driver, maximizes the window and sets it to wait 30 seconds before timing out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestInitialize()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyTestInitialize()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; ChromeDriver();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Manage().Window.Maximize();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now comes the actual test. We navigate to a URL and then compare the title of the page loaded with a know value with a Assert statement like you would find in a unit test.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; CheckBrowserTitle()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Navigate().GoToUrl(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.baseURL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Assert.AreEqual(&lt;span style="color:#e6db74"&gt;&amp;#34;Home Page&amp;#34;&lt;/span&gt;, driver.Title);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally we need to tidy up after ourselves.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;[TestCleanup()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; MyTestCleanup()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver.Quit();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are used to writing tests you will know that the are usually constructed in three sections Arrange, Act and Assert. The Arrange is done in the initialize method, which makes the actual test much simpler, the first line does the Act and the last line does the Assert.&lt;/p&gt;
&lt;p&gt;Now we have written a simple test lets look at something more complex.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;driver.FindElementByLinkTest(&lt;span style="color:#e6db74"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This finds any Link on the page which is click. Be careful as the string need to be exactly what appears on screen it may well be easier to specify by id or class or something that doesn’t change as often. By adding .click() on the end of this command Selenium will click on the link and you can navigate to a new page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about submitting form data?&lt;/strong&gt; Well you can find the element you want to fill in and add .SendKeys(&amp;ldquo;example text&amp;rdquo;) or .Submit() and this will fill in and submit form data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about a screenshot?&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Screenshot ss = driver.GetScreenshot();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ss.SaveAsFile(&lt;span style="color:#e6db74"&gt;&amp;#34;test.jpg&amp;#34;&lt;/span&gt;,System.Drawing.Imaging.ImageFormat.Jpeg);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I have only just started playing around with web UI tests but you can see there is a fair bit you can do.&lt;/p&gt;</description></item><item><title>Mobile App UI Testing</title><link>https://blog-test.funkysi1701.com/posts/2018/mobile-app-ui-testing/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 08 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/mobile-app-ui-testing/</guid><category term="Android">Android</category><category term="Azure">Azure</category><category term="App">App</category><media:content medium="image" type="image/png" url="https://blog-test.funkysi1701.com/images/2018/01/01-newproject-vs.png"/><description>&lt;p&gt;Since I started creating an android app I have been writing simple UI tests.&lt;/p&gt;
&lt;p&gt;I have been taking advantage of the Visual Studio App Center which allows you to test against hundreds of different devices in the &lt;strong&gt;Test Cloud&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Xamarin UI tests" src="https://blog-test.funkysi1701.com/images/2018/01/01-newproject-vs.png" loading="lazy"
width="1371" height="834"
/&gt;
In order to write a UI test create a UI Test App, this makes use of the nuget package Xamarin UI Test. By default you will now have a test called AppLaunches which will take a screenshot of you app after it starts.&lt;/p&gt;
&lt;p&gt;You can now run this test against any device from Visual Studio assuming you have it physically plugged into your machine. However, how do you run against the Test Cloud?&lt;/p&gt;
&lt;p&gt;To run against the Test Cloud you need to first install node.js. Now you can install the appcenter cli with the following command.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;**npm** install -g appcenter-cli
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run the tests in the Test Cloud run the following command&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;**appcenter** test run uitest --app &amp;#34;&amp;lt;username&amp;gt;/&amp;lt;appname&amp;gt;&amp;#34; --devices &amp;#34;&amp;lt;username&amp;gt;/&amp;lt;deviceset&amp;gt;&amp;#34; --app-path _pathToFile.apk_ --test-series &amp;#34;master&amp;#34; --locale &amp;#34;en_US&amp;#34; --build-dir _pathToUITestBuildDir_
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;where &lt;username&gt; is your appcenter username, is the name of your app in appcenter and is the group of apps you have created in app center to test against.&lt;/p&gt;
&lt;p&gt;Look at device sets in the test section of the appcenter and click the new device set button. You can then search for any device you like and add it to a set, as I write this there are 244 devices you can test against.&lt;/p&gt;
&lt;p&gt;It is currently not possible within app center to run tests against a new build, however if you build your app in VSTS as well you can create build or release step that runs it. As the Visual Studio app center is still under development I wouldn’t be surprised if it is added at some point.&lt;/p&gt;
&lt;p&gt;In VSTS look for Mobile Center Test in the definitions and you can specify the same variables as specified in the command line above.&lt;/p&gt;
&lt;p&gt;Now how do you actually write a useful UI test? I mentioned above you get a default test which contains the following code, this takes a screenshot of your app. However you don’t have to include this when using the Test Cloud as screenshots are included for free.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Screenshot(&amp;#34;First screen.&amp;#34;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lets look at what else is included in app&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Repl();
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This starts an interactive REPL (Read-Eval-Print-Loop) which lets you explore what is on screen in your app and pauses execution. I don’t include this in my tests, however I do make use of it to explore what is on screen and what tests I might make use of.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.Tap(c =&amp;gt; c.Marked(&amp;#34;Button&amp;#34;));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This taps an element on screen called Button. There is also a method called TapCoordinates which would allow you to click anywhere you like.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;app.WaitForElement(c =&amp;gt; c.Marked(&amp;#34;View&amp;#34;));
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After clicking a button you are probably going to want to wait for the app to load extra data or a new screen. The WaitForElement waits for an element to appear on screen. There are also methods that wait a period of time or wait until an element no longer exists.&lt;/p&gt;
&lt;p&gt;These are the main methods I have used so far, however there is an extensive list including methods for scrolling, swiping, pinching and adjusting the volume buttons. So you should be able to test all manner of app functionality and if you make use of the Test Clouds will know which devices are causing problems.&lt;/p&gt;</description></item><item><title>Lets see what 2018 can do!</title><link>https://blog-test.funkysi1701.com/posts/2018/lets-see-2018-can/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 01 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog-test.funkysi1701.com/posts/2018/lets-see-2018-can/</guid><category term="Career">Career</category><category term="Family">Family</category><category term="Marriage">Marriage</category><category term="Goals">Goals</category><description>&lt;p&gt;It is 2018 so it must be time to think about what my plans and goals are for the new year.&lt;/p&gt;
&lt;h2 id="buy-a-house"&gt;Buy a house&lt;a class="anchor ms-1" href="#buy-a-house" aria-label="Permalink: Buy a house"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="House" src="https://blog-test.funkysi1701.com/images/2018/LEGO-Classic-10703-Creative-Building-Box-Yellow-House.jpg" loading="lazy"
width="720" height="720"
/&gt;
&lt;/p&gt;
&lt;p&gt;This a huge goal for me. For many years I was content with renting and thought owning my own home wasn’t for me, but then I went and started a family and my career started going in the right direction and my thoughts about this have changed.&lt;/p&gt;
&lt;p&gt;It is going to take a lot of work to make this goal happen in 2018. First I need to save enough money for the deposit, which is far from easy with a wife and two children. Second I need to get our current place sorted ready to physically move which again won’t be easy. Third I need to make a decision which will affect where I live for the next 25 years. At the moment I am torn between the size of property and its physical location, I need to balance both of these and meet the requirements from the rest of the family.&lt;/p&gt;
&lt;p&gt;I do think this is an achievable goal so wish me luck.&lt;/p&gt;
&lt;h2 id="progress-in-my-career"&gt;Progress in my career&lt;a class="anchor ms-1" href="#progress-in-my-career" aria-label="Permalink: Progress in my career"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I need to be careful how I phrase this in case past, current or future employers are reading. I have been working hard at my current role for over a year and I am starting to wonder what is next for me. I am not entirely sure what form this is going to take yet, I have a few ideas on the go and hopefully I can reveal more soon.&lt;/p&gt;
&lt;p&gt;Another one that is very achievable, as long as I have it in the back of my mind as the year goes on progress should be made.&lt;/p&gt;
&lt;h2 id="see-more-of-family"&gt;See more of family&lt;a class="anchor ms-1" href="#see-more-of-family" aria-label="Permalink: See more of family"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently missed a family celebration due to the expansion of my own family and it reminded me that there are aunts, uncles and cousins that I haven’t seen in years and it would be nice to reconnect. Also as my own boys get older and are learning to interact it would be great if they could get to know my own family better.&lt;/p&gt;
&lt;p&gt;I don’t have a clear idea how to achieve this one as it takes two but I am going to make more of an effort.&lt;/p&gt;
&lt;h2 id="celebrate-5-years-of-marriage"&gt;Celebrate 5 years of marriage&lt;a class="anchor ms-1" href="#celebrate-5-years-of-marriage" aria-label="Permalink: Celebrate 5 years of marriage"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Wow how has it been five years since we got married? At some point in 2018 I will take time out from the usual and spend it with the wife away from the boys. I won’t give away more details as I want that to be a surprise.&lt;/p&gt;
&lt;h2 id="celebrate-the-birth-of-my-two-sons"&gt;Celebrate the birth of my two sons&lt;a class="anchor ms-1" href="#celebrate-the-birth-of-my-two-sons" aria-label="Permalink: Celebrate the birth of my two sons"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Celebrate James and Edward" src="https://blog-test.funkysi1701.com/images/2018/james5.jpg" loading="lazy"
width="1080" height="810"
/&gt;
&lt;/p&gt;
&lt;p&gt;I don’t want to get my boys christened as I would like them to make up their own minds when they are old enough, however I do want to celebrate all that they are with a thanksgiving service. Not sure when we are going to sort this, however it is my hope that it will be soon.&lt;/p&gt;
&lt;h2 id="family-holiday"&gt;Family holiday&lt;a class="anchor ms-1" href="#family-holiday" aria-label="Permalink: Family holiday"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not much of a goal but in the summer I will take time out to spend a week away with the family. In previous years we have done scotland, wales and northumberland. This year I am thinking of somewhere not too far away as Edward is still small, but maybe near where I grew up.&lt;/p&gt;
&lt;h2 id="lightning-talk"&gt;Lightning Talk&lt;a class="anchor ms-1" href="#lightning-talk" aria-label="Permalink: Lightning Talk"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A lightning talk is a very short talk or presentation given at a conference or user group. Friends of mine are having lots of success talking about what they know about and I think it might be time for me to have a go. I am not a natural public speaker so this is a step out of my comfort zone, however I am going to start small and see what happens. At the moment I don’t know what my subject or topic is going to be, my suspicion is that it will be devops related as that interest me more but watch this space.&lt;/p&gt;</description></item></channel></rss>