tag:blogger.com,1999:blog-30338381734456674492024-02-18T18:12:55.485-08:00soft circuitryElectronics meets software, A mix of mostly digital electronics, microprocessor projects on AVR, hacking in C/C++C# and PoSH. Thrown in is some commentary on the Digital World to taste.Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.comBlogger159125tag:blogger.com,1999:blog-3033838173445667449.post-42164408297698782372023-01-13T12:35:00.000-08:002023-01-13T12:35:42.971-08:00A shutdown hobby turned mission<p><span style="font-size: medium;">The birth of the goal. A mission, which I have kept to myself till now. About 300 yards from our Victorian mid-terrace, is the 6 bell StPeters, Wilburton, Cambridgeshire, infrequently rung. We grew up abroad so the novel sound nearby one day during the big shutdown had us listening and naively thinking, aah, that can't be too hard to do? My better-half jumped onto google and a while later we started learning, 5 miles away at Stretham StJames, which is a REC (Ringing Education Centre). It's been over a year now, learning a skill is much slower at age 50, and I have finally passed my ART level 1. Frustratingly slow and sometimes I think that not being either musical or mathematical have slowed me down too. But that first lesson turned the lockdown hobby into a mission. To ring my own church bells myself. Every time I hear ringing, I run down the road and sneak in to watch for a bit. Just this week was our district AGM, so we are now guild members too, in fact my smart wife has got a place on the district committee already.</span></p><p><span style="font-size: medium;">So I'm now attached to my training tower officially, 5 miles away, which does not have a full band yet. Last Sunday we only rang the middle 4 there for example, so I'm still a very long way off from achieving my mission of ringing my local tower with the band I belong to. But for me that mission, even though I'm unlikely to ever be skilled enough to ring a full peal like the wonderful visiting band that first got me curious did, is much nearer now. </span></p><p><span style="font-size: medium;">And I'm super excited about that, perhaps because learning has energised me personally. I'm a bit ringing crazy people tell me, and I don't mind. I'm pretty sure it has been good for my back pain and keeping me mobile. In fact I have started another ringing "mission" already, because just having a goal has been so positive for me. More on that mission which involves microphones, some other time.</span></p><p><span style="font-size: medium;">by Conrad Braam, married to Rowan Braam</span></p><p><span style="font-size: medium;"><br /></span></p><div><br /></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-77150518390999995962022-12-31T10:20:00.005-08:002022-12-31T10:21:17.592-08:00wild cam jpeg<p> # better keyframes, and better bitrate</p><p>d:\tools\ffmpeg\bin\ffmpeg.exe -f image2 -loop 1 -i "webcam%02d.png" -re -f lavfi -i anullsrc -vf format=yuv420p -c:v libx264 -pix_fmt yuv420p -g 50 -c:a aac -crf 1 -r 5 -b:a 128k -f flv rtmp://a.rtmp.youtube.com/live2/<stream key-here></p>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-75013255529573650612021-07-09T04:05:00.006-07:002021-07-09T04:05:45.650-07:00convert jpeg to animated gif<p> I ran into a weird issue when the number of frames in the gif gets a bit high.</p><p>https://superuser.com/questions/1638739/convert-images-to-gif-error-marking-filters-as-finished?noredirect=1#comment2530100_1638739</p><p>So tomorrow I'm going to try and weekend-warrior my way through it all and work out why my images were coming out blurry, when they used to be quite passable before.</p><p><br /></p>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-4293846152892583002021-04-05T03:29:00.002-07:002021-04-05T03:29:19.540-07:00Saw chain sharpening notes<p> </p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkC3RWqHu4ffiNR5PBHiNIIpRAzzi4S47drknjiN7BpC-FAZoH4Co1V3tXhGjom5on5iTSGHMma4zEAm0oYgEqNxWhv1slMZOFVRjPRuUWXTlXVL4idFVol4csLqknRDHo3641dfGZf2I/" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="1536" data-original-width="2048" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkC3RWqHu4ffiNR5PBHiNIIpRAzzi4S47drknjiN7BpC-FAZoH4Co1V3tXhGjom5on5iTSGHMma4zEAm0oYgEqNxWhv1slMZOFVRjPRuUWXTlXVL4idFVol4csLqknRDHo3641dfGZf2I/" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">chain depth gauges</td></tr></tbody></table>So today it's sharpening the chainsaw or "saw chain" sharpening notes day.<p></p><p>I loaned a machine similar to this one in the video right at the bottom and used that as a tutorial. All photos here are mine own. This is a titan 20" <a href="https://www.screwfix.com/p/titan-ttl760chn-50cm-49cc-petrol-chainsaw/687fh">https://www.screwfix.com/p/titan-ttl760chn-50cm-49cc-petrol-chainsaw/687fh</a> petrol unit. I have an electric saw, but that is a self-sharpener, so not relevant here today. If you are in a hurry, just scroll down to the video at the bottom.</p><p>I also looked at the hand sharpening, and as in many of the videos I found a discrepancy, most people sharpen at 30° , even though when I checked, my manufacturer states 25° angle. If going by hand is your thing <a href="https://www.youtube.com/watch?v=SzjmpNTVH6U">https://www.youtube.com/watch?v=SzjmpNTVH6U</a> shows how to use a neat little hand sharpener. Once again people don't use the same angle, so check and decide once.</p><p>However I had this tool available to me to loan, so off I went. It takes a while to get the grinding disk end-stoppers set up for your specific chain, remember your chain will also stretch over time. You can also be using this exercise to inspect your chain. You don't want a chain flying off. inspect regularly for damaged links.<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYFBahncaTreNkNNEjanRFGuhsWTcpmtzU1kpQMq0cmTmyLoFqeHaM_s9_dcfCiTGTKYIDOQbUl9gADNJn2cFZOr_qQY4-U4gx1xK1zxsAXddGZ256RCKRI-1NZmRWHuF6jBWqdThPd7c/" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="2048" data-original-width="1536" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYFBahncaTreNkNNEjanRFGuhsWTcpmtzU1kpQMq0cmTmyLoFqeHaM_s9_dcfCiTGTKYIDOQbUl9gADNJn2cFZOr_qQY4-U4gx1xK1zxsAXddGZ256RCKRI-1NZmRWHuF6jBWqdThPd7c/" width="180" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">clamped in a bench vise with a jig<br /></td></tr></tbody></table>This is a pic of me doing the second set of sharpenings on the other side. I had to modify my jig or block of wood for this opposite set of cutters, since it needs a channel for the blade to drop through now. You can see that a bit closer up here. The teeth on a china alternate, so every other tooth cuts to an opposite side to eject the swarf and satay centered in the cut. There is a rather weird moment which, when you are sharping a chain, when you notice that the chain might not have an even number of teeth, which means 2 teeth on one angle will be right next to each other.<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNWM5aw1dvg7Id2KfPXNSMMFZhF4SpqPM97MG8mcYgmeP5nr1kGqnGAF9hVcPWV91d0atP7-P61Nptdm8V8-urBEBe6S9BiE8im2foyEciM4FwbXiUtb6KeaHPvdweaTCfEonOK2kuH88/" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="1724" data-original-width="2048" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNWM5aw1dvg7Id2KfPXNSMMFZhF4SpqPM97MG8mcYgmeP5nr1kGqnGAF9hVcPWV91d0atP7-P61Nptdm8V8-urBEBe6S9BiE8im2foyEciM4FwbXiUtb6KeaHPvdweaTCfEonOK2kuH88/" width="285" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">closer up</td></tr></tbody></table>And also showing the partial jig, with cutaway for the blade to drop through. I could not find a really big block of wood for the job, <span style="text-align: center;">since it really needs to support the entire machine</span></p><p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKBiaP-GC8r6VS7CdVQU6_zbbK2bqwfupBYeFB5QA6wzCyp6l0YQ4mkpBrUmw7M4YOfjSV0mCY_QxyCdPGrFSNATXlagvJfFjqnmsbw2vyHWe15KNUCw_1lYBIxlrEvF59DJJm2EOJD0/" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="2048" data-original-width="1536" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKBiaP-GC8r6VS7CdVQU6_zbbK2bqwfupBYeFB5QA6wzCyp6l0YQ4mkpBrUmw7M4YOfjSV0mCY_QxyCdPGrFSNATXlagvJfFjqnmsbw2vyHWe15KNUCw_1lYBIxlrEvF59DJJm2EOJD0/" width="180" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">this jig was not great, but worked fine</td></tr></tbody></table>It took me an hour just to clean the saw, and sharpen again, but afterwards I had a few large logs and a few small logs diced up. This sawdust pile was me cutting a log in half instead of splitting it, since I just don't have the back muscles for the maul these days. I know, it means less wood, but it gets it dried.</p><p><br /><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA79sNNkrOFsE2p7emcFE3Z7WUIprhDcrYa3XpCGOXO3q6dVl7nKgByFhdRkXXF-G7HQp7m2lVACeuDl2XctlAbFiKGS_pf6AohYgKBs3etNwvC29rY0c_7bOGjI2Y206sF_bwdMG7tMc/" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="2048" data-original-width="1536" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA79sNNkrOFsE2p7emcFE3Z7WUIprhDcrYa3XpCGOXO3q6dVl7nKgByFhdRkXXF-G7HQp7m2lVACeuDl2XctlAbFiKGS_pf6AohYgKBs3etNwvC29rY0c_7bOGjI2Y206sF_bwdMG7tMc/" width="180" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">my sawing block</td></tr></tbody></table>I use an old Pallet which was quite sturdy when it started, but it is used as a splitting base, so it takes a lot of hammering and a beating when the splitting maul ploughs right through a log. but is also convenient when cutting large logs with the chainsaw. So long as you watch for nails!</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/lUOJ4m0jwjM" width="320" youtube-src-id="lUOJ4m0jwjM"></iframe></div>So, here we go finishing with this clip that shows how to do it with a very similar sharpener.<br /><p>I hand-filed the depth gauges by touching them each 3 strokes with a flat file, being careful to "guard" the teeth, which are pretty closeby with some thick heavy gloves, and NO you cannot adjust the raker/depth and then sharpen, the blades are not cut to work that way at all. Don't do it!.</p><p>I now have an appreciation for how blunt a blade gets when it is cutting wood that has dirt on it.<br /></p>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com5tag:blogger.com,1999:blog-3033838173445667449.post-49023449883369117692021-02-15T04:33:00.002-08:002021-02-15T04:33:54.290-08:00Raising Bugs<p> As a software tester, I find myself raising issue tickets , suggestions and even diagnosing bugs for other people's software. Often. Not a week goes by without something not being right. Last week it was the broken Unity installer app. </p><p>Basically Unity fails to install if the bootstrap downloader is not on the same drive as the target install. Which is a problem for people like me who boot off of an SSD and do not want to have huge apps install on their system volume. Took me a while to find that the installer was reading the wrong Windows setting so just ended up running it all on my HDD. But why?</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjg0_kBhlvukIaUjwPSqn91pynPnRwp9HRJgs88I4_Cm-y5zNkfu_7xrs7inond-OWIzrlB9bxk1Xv8_8jYG1-dyyJ3pPUcQWhB7KrTk-nsu4kFXND-Ld0CjcPxTyK8_16DpNUn_95DAY/s944/914328.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="644" data-original-width="944" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjg0_kBhlvukIaUjwPSqn91pynPnRwp9HRJgs88I4_Cm-y5zNkfu_7xrs7inond-OWIzrlB9bxk1Xv8_8jYG1-dyyJ3pPUcQWhB7KrTk-nsu4kFXND-Ld0CjcPxTyK8_16DpNUn_95DAY/s320/914328.jpg" width="320" /></a></div><div><br /></div>Anyway, this was only interesting, because this week I had to install the NVidia Experience App. Now the Geforce experience is not brilliant, it's at times a slow and cumbersome app that scans your computer for installed games in the background and seems to think that that's the only thing it needs to do well, and they never bothered to do some analytics and discover that most people install the suite because it gives them Shadowplay screen recorder, which is a very nice screen recorder (but has some bugs)<div><br /></div><div>Anyway, NVidia seem to have the same Bug Unity have, and you have to change your default install path registry keys to point to C:\programdata not D: else Geforce install just fails with an exit code 3 in a messagebox and suggest rebooting to fix the issue. That's 2 bugs in one, a stupid errorcode message, and a stupid underlying installer defect.</div><div>After a support chat session once again, I did find a resolution, but I have to wonder who triages these bugs? I would hate to be on the receiving end. The games industry never take bugs seriously anyway, but I'll bet they have to put up with a load of vitriol.<br /><p>My bugs? Well my failure this week was me recording take 2 of a tutorial with my microphone on mute. #FailArmy celebration deluxe.</p></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-45123094940438975822020-10-26T01:31:00.003-07:002020-10-26T01:35:20.814-07:00Test automation failure<p> The reason I'm writing this up is mainly to remind myself of how blind I can get. So don't expect to feel sympathy.</p><p>This all starts with a project to test Windows graphics drivers on a beta project. In order to deal with a CI issue which was failing to catch issues with the driver "silently" not installing in the test environment, I hatched a plan. My idea was that it would be quick and easy to build a machine that boots off a clean OS image to solve the problem where a driver fails to really uninstall after the last test run. So we get to test that a clean first-time install works. The trouble is, that it needed to be a real machine, so no VM's allowed, since this was a real graphics driver under test. In retrospect, I should have used something like Norton Ghost disc imaging, and busted my plan quicker, but I didn't.</p><p>I got down a rabbit hole and opted on some dedicated hardware, needed a SSH connection to control it, got that working, needed Python test tool to control it, did that with some conversion between Python and Powershell. About 3 weeks in, all working solo, it all starts loosing plot. Because when I end-to-end demo I notice timing problems, so I got onto it and work out a way to resolve those. Which in turn blinded me to an assumption in my golden OS image. And that's where it went wrong.</p><p>After updating to a fresher image all of the assumptions and test points I had used to verify that drivers were loading and unloading fell apart. Quite a few mistakes were made, and I was to blame because I had worked on most of this code solo. I did after all know what I was doing, and the whole time I was thinking that having some CI with early warning installer testing, would be valuable to the team. I kinda bought my own cool aid, drank it and paid for it.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPflQODWk9cUXJtOGHvySexENNiP9YYs4Sn0B_77464u7jdWfcB_PRjevVUm8JviyxZjhDJ7RI725nJTYiPceZ3YHoJa_oft1w2xJC5or4Gw6HtWfTUSHl0i5uljxtvw5GgfbgC4Q_Euo/s2016/20201026_080846.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Experiences of Test Automation Dorothy Graham Mark Fewster" border="0" data-original-height="2016" data-original-width="1512" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPflQODWk9cUXJtOGHvySexENNiP9YYs4Sn0B_77464u7jdWfcB_PRjevVUm8JviyxZjhDJ7RI725nJTYiPceZ3YHoJa_oft1w2xJC5or4Gw6HtWfTUSHl0i5uljxtvw5GgfbgC4Q_Euo/w300-h400/20201026_080846.png" width="300" /></a></div>I believe that everyone has to make mistakes in order to learn from them. My really human fail is to often write off anyone who makes the same mistake more than a few times. Spectacular failures are not something to celebrate normally, but by doing so, we help other people to not spend quite so much time berating themselves for their error. Time better spent striking while the iron is hot.<div><br /></div><div>Now go, automate, fail early, often and learn.<br /><p><br /></p></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-75294868927670284392020-10-12T09:25:00.000-07:002020-10-12T09:25:09.153-07:00Selenium Page Objects 2 of 2<p>So in part 2 I'm introducing the chaining of pages, this is all about how one object (page) seamlessly hands responsibility to another page. By now you need to almost think of pages and objects as one and the same.</p><p>One of the biggest problems in any GUI type testing is that often you need to visit a few different dialogues in an app to set up initial system state. Even before you can run your actual test check. Something that is a few steps or pages and becomes a mini-test in itself, or in unit testing parlance a "fixture".</p><p>Please be sure to <a href="https://softcircuitry.blogspot.com/2020/10/selenium-page-objects-1-of-2.html">read part 1</a> first where I talk about the simple problem, driving web pages or dialogs as objects in your Python script with helpers that make all of the fields in pages. Dynamic variables in the object (Page) that correspond to each field on the page lets you simply get or set in order to populate form fields or click on buttons.</p><h3 style="text-align: left;">Part 2 chaining pages together.</h3><div><a href="https://github.com/zaphodikus/PageObjectModel/blob/main/PageChains.py">https://github.com/zaphodikus/PageObjectModel/blob/main/PageChains.py</a></div><p>This is exactly the same functionality as all the objects in main.py, but this time they support chaining together as well. Here you see this in Action, we have </p><p></p><ol style="text-align: left;"><li>a login page for a username</li><li>another page for the password</li><li>the main app page</li><li>a profile page (with only one button, logout)</li></ol><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLhcW6_lMe72B-tcipPlkeqCqjAtdMmKPFitpo1gkf7I9cxZftKPEgmDq8lIRkzrKueaL1eCfRj7eVLPowFdl4qLqO6VTBhgyFL5nOplNfG-Ex9-I5D_Shv_8RDEuQSi3ySR9CKTdZKEk/s853/login.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLhcW6_lMe72B-tcipPlkeqCqjAtdMmKPFitpo1gkf7I9cxZftKPEgmDq8lIRkzrKueaL1eCfRj7eVLPowFdl4qLqO6VTBhgyFL5nOplNfG-Ex9-I5D_Shv_8RDEuQSi3ySR9CKTdZKEk/s320/login.gif" width="320" /></a></div><div><br /></div>So I represent these pages as 4 objects, and if you want to routinely navigate to the profile page in a test suite, you want to write that code once only just like the "Page" code is only written once.<div>All you do is string them all along in one method.</div><div><br /></div><div><!--HTML generated using hilite.me--><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: white;">@next_page(</span><span style="color: #0086d2;">"DemoProfilePageV2"</span><span style="color: white;">)</span>
<span style="color: #fb660a; font-weight: bold;">def</span> <span style="color: #ff0086; font-weight: bold;">login_to_profile</span><span style="color: white;">(self,</span> <span style="color: white;">username,</span> <span style="color: white;">password):</span>
<span style="color: #0086d2;">"""</span>
<span style="color: #0086d2;"> Does the whole shebang in one go - show how to make sure we always return the object the decorator</span>
<span style="color: #0086d2;"> says we should do.</span>
<span style="color: #0086d2;"> :param username: The user name</span>
<span style="color: #0086d2;"> :param password: The password</span>
<span style="color: #0086d2;"> :return: the profile page</span>
<span style="color: #0086d2;"> """</span>
<span style="color: #fb660a; font-weight: bold;">return</span> <span style="color: white;">self.next(username).next(password).next()</span>
</pre></div>
</div><div><br /></div><div>You might not notice that the Page class DemoProfilePageV2 was undefined at this time, that's because it's declared elsewhere, and we don't want a dependency. This is solved by every class adding itself to a MAP of pages. And by using a "string". </div><div>The decorator next_page() then neatly passes any parameters you give the method through, and always returns you a object that matches the page you expect. Note that we are also relying on each page pulling some state information from the prior page object, namely a ref to the selenium webdriver. So each page helps to spawn it's successor in the chain.</div><div><br /></div><div>This decorator contract makes it easy for someone to know that they actually are getting an object (Page) of the kind they are expecting every single time that they call login_to_profile() . The only way not to, is if the method raises an exception. </div><div><br /></div><div>
<!--HTML generated using hilite.me--><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #fb660a; font-weight: bold;">def</span> <span style="color: #ff0086; font-weight: bold;">next</span><span style="color: white;">(self):</span>
<span style="color: #fb660a; font-weight: bold;">raise</span> <span style="color: white;">NotImplemented(</span><span style="color: #0086d2;">"Must be implemented to return the Chained PageObject!"</span><span style="color: white;">)</span>
</pre></div>
</div><div><br /></div><div>In the example, I've mandated that every page has a next() method, this is not strictly necessary. I also experimented with how well it works to pass all the parameters into the constructor to simplify needing to pass data along the chain, but decide against that as harder to maintain over time in practise.</div><div><br /></div><div>Finally just so you can see what this test does (aside from the animation graphic above) this is the brief output with the dummy WebServer traces the demo requires stripped off.</div><div><p><!--HTML generated using hilite.me--></p><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: white;">[WDM]</span> <span style="color: white;">-</span> <span style="color: white;">Current</span> <span style="color: white;">google-chrome</span> <span style="color: white;">version</span> <span style="color: white;">is</span> <span style="color: #0086f7; font-weight: bold;">86.0</span><span style="color: white;">.</span><span style="color: #0086f7; font-weight: bold;">4240</span>
<span style="color: white;">[WDM]</span> <span style="color: white;">-</span> <span style="color: white;">Get</span> <span style="color: white;">LATEST</span> <span style="color: white;">driver</span> <span style="color: white;">version</span> <span style="color: #fb660a; font-weight: bold;">for</span> <span style="color: #0086f7; font-weight: bold;">86.0</span><span style="color: white;">.</span><span style="color: #0086f7; font-weight: bold;">4240</span>
<span style="color: white;">[WDM]</span> <span style="color: white;">-</span> <span style="color: white;">Driver</span> <span style="color: white;">[C:</span>\<span style="color: white;">Users</span>\<span style="color: white;">cb</span>\<span style="color: white;">.wdm</span>\<span style="color: white;">drivers</span>\<span style="color: white;">chromedriver</span>\<span style="color: white;">win32</span>\<span style="color: #0086f7; font-weight: bold;">86.0</span><span style="color: white;">.</span><span style="color: #0086f7; font-weight: bold;">4240.22</span>\<span style="color: white;">chromedriver.exe]</span> <span style="color: white;">found</span> <span style="color: white;">in</span> <span style="color: white;">cache</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">17</span><span style="color: white;">][POM]</span> <span style="color: white;">pre_navigate:http://localhost:</span><span style="color: #0086f7; font-weight: bold;">8080</span><span style="color: white;">/loginuser.html</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">17</span><span style="color: white;">][POM]</span> <span style="color: white;">__setattr__</span> <span style="color: white;">editUserName</span> <span style="color: white;">=</span> <span style="color: #0086d2;">'user'</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">17</span><span style="color: white;">][POM]</span> <span style="color: white;">__getattr__</span> <span style="color: white;">btnContinue</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">18</span><span style="color: white;">][POM]</span> <span style="color: white;">__setattr__</span> <span style="color: white;">editPassword</span> <span style="color: white;">=</span> <span style="color: #0086d2;">'pass'</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">19</span><span style="color: white;">][POM]</span> <span style="color: white;">__getattr__</span> <span style="color: white;">btnLogin</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">20</span><span style="color: white;">][POM]</span> <span style="color: white;">__getattr__</span> <span style="color: white;">btnProfile</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">20</span><span style="color: white;">][POM]</span> <span style="color: white;">__getattr__</span> <span style="color: white;">btnLogout</span>
<span style="color: white;">[</span><span style="color: #0086f7; font-weight: bold;">16</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">13</span><span style="color: white;">:</span><span style="color: #0086f7; font-weight: bold;">21</span><span style="color: white;">][PB]</span> <span style="color: white;">teardown:</span> <span style="color: white;">quit</span> <span style="color: white;">chromedriver</span>
</pre></div>
<p></p><p>[WDM] is the webdriver Manager which keeps chromedriver up to date</p><p>[POM] is page object model base class</p><p>[PB] is the test fixture class</p><p>Probably in a real implementation, you might want to not print passwords, even test passwords. So any values that perhaps match "pass" or "password", you replace with ****. I'll leave that up to you the reader to add.</p></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-45413202597789030772020-10-08T10:30:00.011-07:002021-05-26T03:15:43.942-07:00Selenium Page Objects : 1 of 2<div style="text-align: left;">I have been reading a wayback machine page by Adam Goucher describing how to use Selenium page objects in Python. It's the best proper solution of a problem a lot of bloggers have glossed over and presented a partial pattern for. Even the MAN page for the Python/Java pagefactory module is pants, and glosses over the #1 issue, you want maintainable, debug-able test code that tells you useful things about the app under test. I have found that tool docs often state the obvious anyway, and like so many blog posts about how to use page-object model, nobody is getting REAL.</div><h4 style="text-align: left;">Enemies</h4><div style="text-align: left;">Almost nobody is sharing their good "conventions" tricks, nor the battle with enemies of scale they encountered. Enemies which example blog posts never warn you about. So I'm going to spread this over 2 or 3 posts, but let's cover the core and then get to the deeper chaining and workflow problem in part 2.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-jUY3oLLoFt33KZ0RWCKIcyvyoNnWX-iHJ3dpCBREMbLO5MP1vrCSg7kIjObAWicu9CAwHn7lOOWeDXkNP4eMADZhrJXg-FahbPDwDyUm5jw1-xodb-y5W4ooqv_FaZLhheOWbY9CpCI/s853/login.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="853" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-jUY3oLLoFt33KZ0RWCKIcyvyoNnWX-iHJ3dpCBREMbLO5MP1vrCSg7kIjObAWicu9CAwHn7lOOWeDXkNP4eMADZhrJXg-FahbPDwDyUm5jw1-xodb-y5W4ooqv_FaZLhheOWbY9CpCI/s320/login.gif" width="320" /></a></div><h4 style="text-align: left;">Fowler</h4><p>I have chosen Python here, but this pattern applies in Java just as nicely. The best possible intro was written up by Martin Fowler. <a href="https://martinfowler.com/bliki/PageObject.html">https://martinfowler.com/bliki/PageObject.html</a> Fowler even mentions the selenium pattern implementation, with a note on assert style.</p><p>One of the biggest problems in any GUI type testing, is that often you need to visit a few different dialogues in an app to set up initial states. It is possible to use back-end API calls to set initial state too, if your context says it's better to do that, then do that. Something however, getting the browser and app to a point where a test is ready to start, becomes a mini-test in itself, or in unit testing parlance, a fixture. But before we go there, lets share my findings after a bit of Googling for better solutions and a good Python starting point.</p><h4 style="text-align: left;">Goucher</h4><p>From the Pragmatic Programmer tutorial written by <span face=""Noto Sans", Helvetica, Arial, "Microsoft YaHei New", "Microsoft Yahei", 微软雅黑, 宋体, SimSun, STXihei, 华文细黑, sans-serif" style="background-color: white; color: #6f6f6f; font-size: 14.4px; font-style: italic;">Adam Goucher. :</span></p><p><a href="https://web.archive.org/web/20190428004331/https://pragprog.com/magazines/2010-08/page-objects-in-python">https://web.archive.org/web/20190428004331/https://pragprog.com/magazines/2010-08/page-objects-in-python</a></p><div style="text-align: left;"><div style="text-align: left;">This appears to point to a Python pagefactory module, the post by Adam Goucher seems to have gotten deleted at some point. Hurrah! to the wayback minions. Please read the above link before continuing....</div><div>If you have read the above wayback link, lets continue. Here is the example test code the original module author gave:</div></div><p style="text-align: left;"><span face=""Noto Sans", Helvetica, Arial, "Microsoft YaHei New", "Microsoft Yahei", 微软雅黑, 宋体, SimSun, STXihei, 华文细黑, sans-serif" style="color: #6f6f6f; font-size: 14.4px; font-style: italic;">selenium_unittest.py:</span></p><p>
<!--HTML generated using hilite.me--></p><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #fb660a; font-weight: bold;">def</span> <span style="color: #ff0086; font-weight: bold;">login</span><span style="color: white;">(self):</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;"># set_text(), click_button() methods are extended methods in PageFactory</span>
<span style="color: white;">self.edtUserName.set_text(</span><span style="color: #0086d2;">"opensourcecms"</span><span style="color: white;">)</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;"># edtUserName become class variable using PageFactory</span>
<span style="color: white;">self.edtPassword.set_text(</span><span style="color: #0086d2;">"opensourcecms"</span><span style="color: white;">)</span>
<span style="color: white;">self.btnSignIn.click_button()</span>
</pre></div>
<p></p>
<p>Adam starts by fixing the bug in the selenium sample code by parameterising the login function in his post. There are a whole raft of tiny issues to be had with the selenium wrapper, mainly around extensibility, so I discarded it very early on.</p><h4 style="text-align: left;">Syntactic sugar</h4><p>The first thing we see is that the PageFactory module assumes you initialise a member in your class called "driver" so it can talk to selenium. Fair enough. It also then wants you to add a dictionary of locators, which get automatically turned into class attributes using python __getattr__() . And finally you can add methods to your class as you expect to encapsulate a real world test. This sounds like a recipe that wants a bog standard base class.</p><p>I got disappointed by the module not addressing the issue the webElement interface set_text() method that for high-level use and simplicity really needs to implicitly do a clear() before the set_text() for readability. I addressed this by implementing a __settattr__() which does a clear() of the editbox, and send_text() all in one go. As you progress along, you will also find that sometimes you want to drive a element on the page which is not currently in view, the scrolling problem. Most of the time, you want the test to do what a human would do, scroll to the element and then interact with it automatically, inside the set()/get(), so that you don't litter your test code with scrolling code. There are many pitfals in web app automation using selenium that other higher level frameworks try to solve for you. ActionChains sound like the right solution to page scroll issues, but trust me, javascript to scroll to elements is more reliable.</p><p><i><span style="color: #999999;">a better login( )</span>
</i></p>
<!--HTML generated using hilite.me--><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"> <span style="color: #fb660a; font-weight: bold;">def</span> <span style="color: #ff0086; font-weight: bold;">login</span><span style="color: white;">(self,</span> <span style="color: white;">username,</span> <span style="color: white;">password):</span>
<span style="color: white;">self.email</span> <span style="color: white;">=</span> <span style="color: white;">username</span>
<span style="color: white;">self.password</span> <span style="color: white;">=</span> <span style="color: white;">password</span>
<span style="color: white;">self.btn_login.click()</span> </pre></div>
<p></p>
<p>At a later stage I also started to follow a locator naming convention, and I swapped out "btn_login" in preference of a name-<type> and called it login_button. </p><p>And now out login() has parameterised instead of hard-coded the password here as Adam showed us already. I'm going to go farther than just the convenient login() function, because it deals with a fundamental difficulty with the locators collection and intellisense, the job of writing code without knowing the names of elements. I am going to suggest every form (class in Python) has a submit() method, for consistency, and then go on to suggest that every form also has a populate() function . This defends our tests, whenever the form starts getting busy or even fragile due to constant app under test change. Less repetition of test code that populates the form (DRY principle), improves maintainability and mostly test readability. But what, you might say about negative login tests? Like a blank password?</p><h4 style="text-align: left;">App conventions</h4><div>Our login() function may/might raise an exception if the password is empty or the username is empty. The button normally takes you to a new web page, I'll get to that in part #2, for now let's stay focused on the login problem as an example. This brings up the point about test code that is assertive versus test code that is not assertive. The former tactic makes writing negative test cases easier to do, often at a point in your project where rewriting code has become expensive. The page objects are a "layer", don't let the layer get in your way, only raise exceptions when a contract the object provides would break.</div><div><br /></div><div><todo disabled form button screenshot></div><div><br /></div><div>We might be starting to enforce UX rules in our test code, about whether buttons on forms should be disabled until a form is filled out now. Don't bake this kind of UX decision into your pageobject tool, rather enforce it in a helper method if that will help you achieve consistency. At this point you can add code to the login function to also check if an error message get displayed when the username was for example empty or password not meeting a required strength. </div><h4 style="text-align: left;">Waits</h4><p>The other thing I did in my page factory implementation is have the page object constructor wait for the page to load by waiting for all of the locators to be present instead of still requiring you write a WebDriverWait callable first, to handle the page load time problems all in one go.</p>
<p>So the rest of my page object is not really code, and looks like this:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(17, 17, 17); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #fb660a; font-weight: bold;">class</span> <span style="color: white;">PageLogin(PageObjectBase):</span>
<span style="color: #0086d2;">"""</span>
<span style="color: #0086d2;"> The new social login page</span>
<span style="color: #0086d2;"> """</span>
<span style="color: white;">locators</span> <span style="color: white;">=</span> <span style="color: white;">{</span>
<span style="color: #0086d2;">"login_button"</span><span style="color: white;">:</span> <span style="color: white;">(By.XPATH,</span> <span style="color: #0086d2;">"//span[contains(.,\'Log in\')]"</span><span style="color: white;">),</span>
<span style="color: #0086d2;">"email"</span><span style="color: white;">:</span> <span style="color: white;">(By.ID,</span> <span style="color: #0086d2;">"email"</span><span style="color: white;">),</span>
<span style="color: #0086d2;">"password"</span><span style="color: white;">:</span> <span style="color: white;">(By.CSS_SELECTOR,</span> <span style="color: #0086d2;">"#password"</span><span style="color: white;">),</span>
<span style="color: white;">}</span>
</pre></div>
<p>On the topic of locators, I found a small problem space with disabled and hidden controls that only appear later, or are dynamic, in cases where a page change state. Now you could argue for making separate pages when that happens, but it's illogical to do so in terms of mental overhead, code complexity and how to deal with backtracking of state.</p><p><todo: show how we added a list of mandatory locators to deal with hidden ones at page load time></p><p>Here is the code <a href="https://github.com/zaphodikus/PageObjectModel">https://github.com/zaphodikus/PageObjectModel</a> , this includes sample html pages, a mini Webserver and a few other tests to play with. </p><p>The real interesting part of this completely standalone test test suite is however <a href="https://github.com/zaphodikus/PageObjectModel/blob/main/PageFactory.py">https://github.com/zaphodikus/PageObjectModel/blob/main/PageFactory.py</a> </p><p>This implementation copies 2 ideas from other implementations.</p><p></p><ol style="text-align: left;"><li>element highlighting - a magenta drop-shadow gets added to every element we do a lookup on</li><li>animation delay - a settable interval to slow down the automation so you can see what is happening</li></ol><p></p><h4 style="text-align: left;">Enemy of scale</h4><p>In summary</p><p>- easier to maintain code by using page object methods() to encapsulate common tasks like populating or submitting</p><p>- page load "wait" using the same locators.</p><p>- debugging by highlighting the interactive element</p><p>- locator naming conventions</p><p>- helper method conventions</p><p>- __getattr__ and __setattr__ to make managing the web mechanics easy</p><p>Next week in part 2 I'll cover the other parts of this standalone sample, but also the promised solution to simplifying the writing of workflow-like tests that consist of groups of pages that a tester wants to need to execute in a sequence to further remove duplication for common tasks in the web app. I hope this sharing of some code that's actually going in pattern at least, into a live production suite, will help people more than the simple homework answers that are shared in so many blogs.</p><p>(Code syntax highlighting done using <a href="http://hilite.me/">http://hilite.me/</a> )</p>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-11503194052962434072020-09-22T10:52:00.006-07:002020-09-22T10:52:39.621-07:00RICOH SP201N drivers just hard to set up<p></p><h2 style="clear: both; text-align: center;">Bad default address port detection RICOH SP201N drivers</h2><div>The frustrating part is the port name and the address gets prefixed with http here. The driver is unable to make sense of the address so you have to manually strip off the http and the trailing slash down to the bare IP.</div><div>A simple thing to fix in the driver you would imagine, but this is what you get, and it does NOT work.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicDeNHZMGbbWxllmNijU6ywUGYGYLLcHQZRLjqNXI3sZW7WwP6SZOBu95SJ3vyhprSlYqEejKLFMJPppvftRIkquk1ijOoPmiZ4P1JDHUqJvHiYuZ2lCCN1R-r_Nm7QeLgQEEQ9neVMtU/s695/Screenshot+2020-09-22+184658.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="596" data-original-width="695" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicDeNHZMGbbWxllmNijU6ywUGYGYLLcHQZRLjqNXI3sZW7WwP6SZOBu95SJ3vyhprSlYqEejKLFMJPppvftRIkquk1ijOoPmiZ4P1JDHUqJvHiYuZ2lCCN1R-r_Nm7QeLgQEEQ9neVMtU/s320/Screenshot+2020-09-22+184658.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;">incorrect address </div><div class="separator" style="clear: both; text-align: left;">You will however not be able to edit the port without unloading everything, so simply add a new port, correctly, then switch to the new port.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Viola</div><div class="separator" style="clear: both; text-align: left;">The number of times this has spoiled a otherwise perfectly good printer experience, grrrrr.</div><br /> <p></p>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-16857801120683735012020-08-27T12:51:00.001-07:002020-08-27T13:08:36.263-07:00Standing Desk Build<p>Lockdown had many of us trying to figure out how to work from home suddenly and with little warning. Most people who remote work have a day job that they do on just one tiny 22" laptop screen. I'm not a laptop on the bed kind of person.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeRIyadHD0sqemKf6W6mWxn2V6vqUu2ubWertz2gLB52xSN2wqgSr3dbY-HNFWMqTGYtNd8Zj61CBHM8nxlb_MBqRp7l5IhfRcYOyz6ViKRwCX6apXBtvSiTJ5GmhPPM0Mt0YUD26ZblU/s2016/sd4.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="600" data-original-width="2016" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeRIyadHD0sqemKf6W6mWxn2V6vqUu2ubWertz2gLB52xSN2wqgSr3dbY-HNFWMqTGYtNd8Zj61CBHM8nxlb_MBqRp7l5IhfRcYOyz6ViKRwCX6apXBtvSiTJ5GmhPPM0Mt0YUD26ZblU/s640/sd4.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Starting with a recovered pallet</td></tr></tbody></table><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">In the workplace, I've lately been using sit-stand desks on account I'm not getting any younger and mostly neither is my back. Standing is great for bad backs. My physio (which is impossible to visit now in lockdown) told me I have got 2 damaged cushion thingies, and if I work out my life history, I have probably had this problem since age 15, and possibly even from much younger, so it's not going to get better. No use in complaining, but it's still there. If you are still reading that's good, because although I generally the grumpiest sod on the planet, I know it and I'm not gray all the time. Hence this blog post.</span></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT3EF6b9JAv_dtqBCgEA1kmPJE-rvTsnriAFBEICTN8hTwes-82dAnvNpkUTIpSSoOWc3OuKR_mQeyr1UgJtuPV2otXaVrdxbbOY6mS6wYIeeMv8gpAT4-72JQUqD0NuBYdldzohqy6wg/s1780/sd1.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1780" data-original-width="1372" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT3EF6b9JAv_dtqBCgEA1kmPJE-rvTsnriAFBEICTN8hTwes-82dAnvNpkUTIpSSoOWc3OuKR_mQeyr1UgJtuPV2otXaVrdxbbOY6mS6wYIeeMv8gpAT4-72JQUqD0NuBYdldzohqy6wg/s640/sd1.jpg" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Aluminium camping table</td></tr></tbody></table><p style="text-align: center;"><span style="text-align: left;">It's not exactly flexible, and I was sitting on kitchen chair some of the time. Moving everything about take time. Sometimes sitting in a couch just to curl up against the pain, eventually I splashed out big time.</span></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBe6LSq7GGfv0UdVuFA3caLjc8UqU8T1hDKD7w_eRR4k5cfPEM8Ioy_APS0KOzhs1YjOh38ZLSdCBuic3vWfC806MnMA9FO17KMAWYfl8rF76TYk5nxGk2Iwg6MyAr1tDkUy1tZxM1q3E/s2016/sd3.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="600" data-original-width="2016" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBe6LSq7GGfv0UdVuFA3caLjc8UqU8T1hDKD7w_eRR4k5cfPEM8Ioy_APS0KOzhs1YjOh38ZLSdCBuic3vWfC806MnMA9FO17KMAWYfl8rF76TYk5nxGk2Iwg6MyAr1tDkUy1tZxM1q3E/s640/sd3.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Wait for it</td></tr></tbody></table><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN6vlvUfunuzh0V7ipNY1aHly86v9TsuzPlykKn9dfWFh5v7NYYbj_FP-qF2gO9vgTcXEjAvW6aqW1jyh7CONzvCJXVuxK9rdQ0EWofGzl74T9os8Ln2UnxoDFZVOZmoYR8YC6_9Jtowg/s513/sd5.png" style="margin-left: 1em; margin-right: 1em;"><br /><img border="0" data-original-height="247" data-original-width="513" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN6vlvUfunuzh0V7ipNY1aHly86v9TsuzPlykKn9dfWFh5v7NYYbj_FP-qF2gO9vgTcXEjAvW6aqW1jyh7CONzvCJXVuxK9rdQ0EWofGzl74T9os8Ln2UnxoDFZVOZmoYR8YC6_9Jtowg/s0/sd5.png" /></a></div><div class="separator" style="clear: both; text-align: left;">Ignore that big piece of splash out on the 4K monitor. I did not want all the money to got to Jeff, so I went to the nice little website here and got a frame and the cable management snake: <a href="https://flexispot.co.uk/electric-standing-desk-frame-ez1.html">https://flexispot.co.uk/electric-standing-desk-frame-ez1.html</a> . In reality it was pretty long time in choosing which desk I wanted, but I'm limited by living in a small, but not tiny house. I needed to buy the smallest unit with smallest footprint, so it came to a toss up between the EN1 and the better EZ1 model mainly due to cost not being a limit. So this was all back in June, so on payday I put in all of my orders and took a few days of work. Soon the boxes arrived.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOreYjDuY29cjwZFhyfHqu5C8GFMD7hSktxi-Hw5f1eCdj3VIFiPYXa95v6nVJ1J0D8aAVZsABYazu8NRcrcyBlhOPpGFpesqJ4PKDAyFnQJMjFINOF_uysKFOMeJNK0cUMIxRXzKKz_Y/s1283/sd6.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1283" data-original-width="1134" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOreYjDuY29cjwZFhyfHqu5C8GFMD7hSktxi-Hw5f1eCdj3VIFiPYXa95v6nVJ1J0D8aAVZsABYazu8NRcrcyBlhOPpGFpesqJ4PKDAyFnQJMjFINOF_uysKFOMeJNK0cUMIxRXzKKz_Y/w453-h512/sd6.jpg" width="453" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Unboxing<br /></td></tr></tbody></table><div class="separator" style="clear: both; text-align: left;">It's not that hard it assemble this, but to get the desk to be narrower than the specification, you can fiddle the rotating drive bar that drives the far-end gearbox to shorten it. And when you bolt the leg on, instead of 4 bolts, if you slide it all 2 inches up to the next bolt threaded hole, the whole frame is 2 inches narrower. It's still perfectly stable with 2 bolts , and it's not possible to narrow the legs much more without taking a steel-saw to the drive rod to cheat on both sides. So I was not about to modify the desk with a saw, as that would make a return impossible. It's adjustable to wider widths, but I needed the feet to be at most 33 inches due to skirting boards limitations.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Flexispot have got friendly support people, and once I asked the right question I got the right size desk quite quickly, the other customization I did was to not buy the desk top. Due to the space I had, the desk was going to always have to be off-centre. If you buy the nice desktop they sell, it comes pre-drilled I suspect. But I'm a DIY kind of guy!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Actually I took longer to finish this desk because I had to varnish it and do all the cable tray installing. I actually ended up finishing the project during work hours one Monday. Don't tell my boss!</div><div class="separator" style="clear: both; text-align: left;"><br /><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkoW_4yoFZ8jhyphenhyphenL12UxnMASdA7F0C61rYQMCPbTZFdI-5qFWUXSiPo4bOu2f_zfAxlfKgmqBlXgPyTogz6bSDJszXf46iFa83ewvh0jmkDhKhIRSJzqe8PCjJmAt-jVUEM-of7D8i5O2k/s2048/20200630_221750.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1536" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkoW_4yoFZ8jhyphenhyphenL12UxnMASdA7F0C61rYQMCPbTZFdI-5qFWUXSiPo4bOu2f_zfAxlfKgmqBlXgPyTogz6bSDJszXf46iFa83ewvh0jmkDhKhIRSJzqe8PCjJmAt-jVUEM-of7D8i5O2k/s640/20200630_221750.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">All done</td></tr></tbody></table>It's totally off center! On purpose! Here you can see my normal standing position, which is at 106 cm, while the desk goes up to 121 cm. It will drop the bottom of the desk to 71cm, but my sitting memory position is 73cm, so plenty of room for most people to get an ideal fit. A child will struggle and for children I suggest getting a 3 stage model. Downside is that all of the 3 stage models are wider and larger.<div><br /></div><div>On the other hand if you are a child, these make great albeit slightly dangerous blanket forts!<br />So from the picture above, you can start to see some of my DIY work, it's off center because it has to fit around a hearth - which is how Victorian homes or in my case homes without access to gas are heated during winter. And that means there is a small cutout, to let it go up and down around the stove.</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSrGYmGis_wEFSEW3XBGdU7b-j7rLdzLXt48IxgXLzLDF00vHl2ZmKH4KRiXAUEUU9UmHQhuYxiWRNyxn3ojTdEOctfQN69Qnb6-XMTOLLwb-T6Zli06Z8BAoYHYJBIzCBdrwjSZVsJBo/s2048/20200711_144644.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1536" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSrGYmGis_wEFSEW3XBGdU7b-j7rLdzLXt48IxgXLzLDF00vHl2ZmKH4KRiXAUEUU9UmHQhuYxiWRNyxn3ojTdEOctfQN69Qnb6-XMTOLLwb-T6Zli06Z8BAoYHYJBIzCBdrwjSZVsJBo/s640/20200711_144644.jpg" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Underside of desk.</td></tr></tbody></table><div>The clear/white plastic thing poking out of the hub is called spiral binding. I got mine off an electronics supplier years ago in bulk, but this it where most people might start to look to get some : <a href="https://www.amazon.co.uk/dp/B082DZ7455/ref=sspa_dk_detail_8?psc=1&pd_rd_i=B082DZ7455&pd_rd_w=B7Ac7&pf_rd_p=dc37174d-0a14-4209-a295-71b2053f4171&pd_rd_wg=uwCBX&pf_rd_r=AWNGFAXFJY6ZGV22PN8X&pd_rd_r=4dab941e-e831-4ef7-afbc-9e6c36ee6c08&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExQzlEWVlLSDhZV1RTJmVuY3J5cHRlZElkPUEwNDAzMzQ4MkRDWk1TSzlCM1FLMSZlbmNyeXB0ZWRBZElkPUEwNDYwODY5MUdRRzdXUkpVOVFTMyZ3aWRnZXROYW1lPXNwX2RldGFpbF90aGVtYXRpYyZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=">amazon</a> or <a href="https://www.rapidonline.com/hellermanntyton-161-41200-sbpe9-pe-na-30m-spiral-binding-natural-9-0mm-30m-49-7190">rapidonline</a> . In a prior lifetime I was a cabling contractor and fell in love with how quickly it is at tidying up lots of cables while protecting them at the same time. I bought 2 6-gang multiplugs. You can get a 10-way or something if you are prepared to pay more, but cheap as chips you can get 2 sturdy 6-way plugs with different length cords to make it all nice and tidy. Here you can see I bought baskets and screwed them on underneath. NEVER ever let the wall-warts that power something hang vertically or even sideways out of a plug-point. They will pop out at the worst possible time, and a cable tray just makes that an improbably.</div><div><br /></div><div>So one more thing construction-wise to mention here is desk thickness. The desk motor is rated to 75Fg, which it actually does comfortably. I got my teenager at 70Kg to lie on the table with a small dumbell and drove it up and down. It is quite strong. A 12mm top is the minimum usable thickness plywood mainly due to load bearing capacity and being able to take screws without poking through. You can get 12mm screws, which are ideal, but you want to be super careful at every point if you don't go for a formed top or at least 18mm. I originally planned for no monitor arm installation here. If you install a 2 or 3 display monitor-arm system, you want 18mm thickness plywood. Formed tops are prettier, but cost more - I bought 2 "handi-panels" for 30 quid, and used the spare one for a desk riser. I used beech edging, which comes in a iron-on strip and is dead cheap to hide the beautiful "chipboard effect" that plywood has. A hot iron and a craft knife takes all of half an hour to cover up the plywood edge.</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguntvPilqd-tRVSZzON4WzTnZp4SSil_lwzM6o2UpDJ_z_Op9VDJmwGDTVLvOPGAhDEJaR06ytXZb9lhhyphenhyphen2vQLMoC-8OqKSK2lKkVSV3nHZwtvGk-O5NvJ-WzzmYn2eDs7YL_du4PGojA/s2048/20200711_174532.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1536" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguntvPilqd-tRVSZzON4WzTnZp4SSil_lwzM6o2UpDJ_z_Op9VDJmwGDTVLvOPGAhDEJaR06ytXZb9lhhyphenhyphen2vQLMoC-8OqKSK2lKkVSV3nHZwtvGk-O5NvJ-WzzmYn2eDs7YL_du4PGojA/s640/20200711_174532.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">With desk-riser to hide a lot of the cables<br /></td></tr></tbody></table>In the above picture you can see where the corner is chopped out around the stove too. Ha Ha. You also cannot see the holes where all of the cables come up, I have artfully hidden those holes under the riser I made. The rizer is high enough to slip the laptop under it. If I did not slip the laptop out of the way I would be making the desktop deeper, an impossibility only due to my house being really small. I have a large deep and wide desk in my garage, which I made as a teenager, but it just won't fit into most UK homes.<div><br /></div><div>I'm going to stop rambling on now, but finish up with how I am so pleased with my DIY project and if I could change 2 things I would:</div><div><ol style="text-align: left;"><li>Buy the under-desk tower-case holder from flexispot.</li><li>Varnish it with boat varnish, not regular varnish, for hardness.</li></ol><div>Finally my PSA warning, do not use a standing desk while barefoot or wearing regular shoes, you will feel foot pressure and calf pain due to lack of movement. Standing on a highly cushioned object like a gel mat or a just a rolled up picnic blanket keeps your feet moving and the blood pumping.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpMoSjd_Nnhc_1oAwPpKN7-DZEBQgv_3eQW18WCngzReR1rtpMuvp2ItzeipZTw6IeaaGkRxdW-DkOKuc9p39m-Tlg_5EosXq3zUgeNVAODpWB7orvq2gG_-Hf_zXyixatsXIiVevAgWo/s2048/20200827_095058.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1536" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpMoSjd_Nnhc_1oAwPpKN7-DZEBQgv_3eQW18WCngzReR1rtpMuvp2ItzeipZTw6IeaaGkRxdW-DkOKuc9p39m-Tlg_5EosXq3zUgeNVAODpWB7orvq2gG_-Hf_zXyixatsXIiVevAgWo/s640/20200827_095058.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">FINN</td></tr></tbody></table><div><br /><br /><br /></div></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-74792211128056472172020-07-31T07:37:00.001-07:002020-07-31T08:16:47.636-07:00Test Plan Template<div>One of the areas of testing that is often overlooked is how critical communication really is. Your job description as a tester, is not to only do the testing, but to somehow report on it. Something a developer never has to do.</div><div><br /></div><div>A developer has to present an architecture design, to which the test plan is a simile. Although test plans rarely live that long nor look that grand. A developer has to demonstrate their working code, but the tester never gets a demo moment, all they get is Jira tickets. And let's face it, like any agile project, agreement on <a href="http://agilemodeling.com/essays/barelyGoodEnough.html" target="_blank">JBGE</a> . Of course I'm talking about a project where developers also do a lot of the testing itself too, and for this reason a test plan needs to also prevent too much test coverage of risks we do not care about.</div><div><br /></div><div>So now we know why at least on one level, that test plans matter, lets look at writing your plan, and communicating it. It's a dead document unless you use it to support your test report outcome anyway. Effort on plan document would fail you on <a href="http://agilemodeling.com/essays/barelyGoodEnough.html" target="_blank">JBGE</a> criteria if it was not a concise and readable document.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCrb8C7n2cK3hba3OH97Ylra67BpD-uaVaQB4UmRPjfYQJoq5o86DqM8wteI3v-MZjN5n8DZRo7ya0uxrEob2IsxsPaI00yAlv1epTZdLxs1u28_mCUPt0ngxTqjUfa3J22h-NkBVYGyE/s1114/template.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="word document screenshot" border="0" data-original-height="1114" data-original-width="881" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCrb8C7n2cK3hba3OH97Ylra67BpD-uaVaQB4UmRPjfYQJoq5o86DqM8wteI3v-MZjN5n8DZRo7ya0uxrEob2IsxsPaI00yAlv1epTZdLxs1u28_mCUPt0ngxTqjUfa3J22h-NkBVYGyE/w506-h640/template.PNG" title="A one page test plan template" width="506" /></a></div><div><h2 style="text-align: left;">Title and Author</h2></div><div>This gets the metadata out of the way, having a sell-by date on any document, up-front is critical. <br /></div><div><br /></div><div><h2 style="text-align: left;">Introduction</h2></div><div>I'm using a Template presented by Ministry Of Test, in one of their <a href="https://www.ministryoftesting.com/dojo/lessons/the-one-page-test-plan?s_id=158320" target="_blank">free modules here</a> . Keep the intro really short, anyone reading this already knows that the project or feature is, stick to a one-liner like the "unique" goal of the test cycle undertaken.</div><div><h2 style="text-align: left;">Resource</h2></div><div>Describe what kit you will need, and what amounts of time you will need. This is to help you decide what kit you already have, must rent or buy, and to size the work. Any kit you need to "book" needs actions taken earliest, along with time that belongs to other people.</div><div><h2 style="text-align: left;">In Scope</h2><div>At this point, remember that you ideally want this to fit onto one page, sharpen that pencil now. You might just refer to the product requirements doc if there is a good one. Think not functionality, but think behavior or use other frames of reference that condense a description of the testing activity.<br /></div><div><h2 style="text-align: left;">Out of Scope</h2></div><div>This is pretty much a one-liner and a reminder to the tester of any functionality we are not looking at, but was added during the project anyway. Remember time is against you, stick to listing only new behaviour that is delivered, but which you are not going to test. <br /></div><div><h2 style="text-align: left;">New functionality</h2></div><div>Components that have changed or been added. Describe the changes in behavior a user will notice, but also the changes a user will make to how they do/can use the new product version.<br /></div><div><h2 style="text-align: left;">UAT</h2></div><div>Identify who will be responsible for UAT.<br /></div><div><h2 style="text-align: left;">Infrastructure</h2></div><div>This is the bit that probably describes to someone who want to run this test iteration again at a future point, or who wants to learn from the activity afterwards.<br /></div><div><h2 style="text-align: left;">Risks and Assumptions</h2></div><div>Describe what functionality or what behaviors you will do less deep testing in, and why. Describe mitigations for the reduced coverage. For example "We decided not to automate test the SMS message reception for new SIM holders, but instead we tested the emails the system sent and did boundary analyses and used trace logging automation scripts to verify that SMS does get sent out." <br /></div><div><br /></div><span><a name='more'></a></span><div>Here is a <a href="https://drive.google.com/file/d/1-NWsRRHpz5YQDG1yQQHAMXp2dEbBfWha/view?usp=sharing" target="_blank">link to the template</a> in docx. There are a host of other test plan formats, and I also like experimenting with for example using a Trello board and creating tickets for each part of a plan so you can mark them off, and also arrange them in a way that engages the audience. I prefer short and sweet, with some formality. The mind maps form of planning testing is useful, but I have found these are not always easy to explain to someone else afterwards. Mind maps are better in my experience in test analysis - but if your team is comfortable with a way of communicating using something like a mind map, it may be better to discard the proform.<br /></div><div><br /></div><div>If your field requires detailed test documentation, you can use this same format and go really deep. But we are not actually building a house that will stand for 50 years here, so a bill of materials is not needed in my case. Some product fields , or where you are doing external contracted testing will require a lot more detail, down to quoting which specifications you will comply with, regulations and will refer to actual quality criteria docs. Otherwise don't go into detail in the document, detailed lists of what kit you needed, what tools you have to find or to create will be overkill in most projects. Try to timebox the document effort into 10 minutes, for every 1 day you will spend doing this testing.<br /></div><div><br /></div><div>The test plan is a communication document after all, target it not at yourself, but at the stakeholders. It's your version of an architecture diagram with a difference, it shows someone else how you checked that all of the doors, windows and roof did not leak on your new house. Not what materials were used and why, that would be boring.<br /></div></div>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-37042939723528850102020-04-13T04:34:00.001-07:002020-04-13T04:34:32.230-07:00Agile sprints named after Terry Pratchet Discworld novelsI joined a team just as they were running out of titles in the Discworld series. This had me looking at any Pratchet books, in order to keep the names running, and this is where I ended up. A bit of a geeky take on it. The editable raw data is available for updating on github.<br />
<br />
<a href="https://github.com/zaphodikus/terrypratchetsprintnames">https://github.com/zaphodikus/terrypratchetsprintnames</a><br />
<br />
<table border="1">
<tbody>
<tr><th>Title</th>
</tr>
<tr><td><a href="http://www.worldcat.org/oclc/796277033">A Blink of the Screen : collected short fiction</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwlds.htm#hat_full">A Hat Full of Sky</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldw5.htm">Carpe Jugulum</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwldw.htm#eqrites">Equal Rites</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldr3.htm">Eric</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc3.htm">Feet of Clay</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwlde3.htm">Going Postal</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/goodomen.htm">Good Omens</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc1.htm">Guards! Guards!</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldd4.htm">Hogfather</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/526057897">I Shall Wear Midnight</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwldr.htm#inttimes">Interesting Times</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc4.htm">Jingo</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/johnnym2.htm#bomb">Johnny and the Bomb</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/johnny_m.htm#thedead">Johnny and the Dead</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldw3.htm">Lords and Ladies</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwlde4.htm">Making Money</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldw4.htm">Maskerade</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc2.htm">Men at Arms</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwld2.htm">Monstrous Regiment</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldd1.htm">Mort</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwlde1.htm">Moving Pictures</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/nation.htm">Nation</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc6.htm">Night Watch</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/johnny_m.htm#mankind">Only You Can Save Mankind</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwrld.htm#pyramids">Pyramids</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/867916800">Raising Steam^</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/50283198">Reaper Man</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/smllgods.htm">Small Gods</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/703206404">Snuff</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwldd.htm">Soul Music</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/47625356">The Amazing Maurice and his Educated Rodents</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldr1.htm#colour">The Colour of Magic</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc5.htm">The Fifth Elephant</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldr5.htm">The Last Continent</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwldr.htm#lasthero">The Last Hero: a Discworld® Fable</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldr1.htm#light">The Light Fantastic</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwlde2.htm">The Truth</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwlds.htm#weefree">The Wee Free Men</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldd5.htm">Thief of Time</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldc7.htm">Thud!</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldr6.htm">Unseen Academicals</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/61762815">Where’s My Cow?^</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwlds.htm#wntrsmth">Wintersmith</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/dscwldw2.htm">Witches Abroad</a></td></tr>
<tr><td><a href="http://www.worldcat.org/oclc/779864032">World of Poo</a></td></tr>
<tr><td><a href="https://www.hjkeen.net/halqn/discwldw.htm#wyrdsis">Wyrd Sisters</a></td></tr>
</tbody></table>
<br />Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com2tag:blogger.com,1999:blog-3033838173445667449.post-17992900359489938332020-02-19T00:10:00.000-08:002020-02-19T04:45:50.903-08:00Pihole or OpenWRTI am struggling to understand the fascination with the PiHole. Over a WRT real firewall, it's a vastly inferior solution beyond Ad blocking. Which in itself is a dirty problem. Ad blocking users are like strict vegans in my books. Saving all those pigs and cows, but they are still there in plain sight for the rest of us.<br />
<br />
I am trying to create a test or simulation network that simulates a Corporate LAN with limited egress ports and address wise. The Pihole is useful because it is a DNS only solution, but when the device under test is not under complete control, you cannot use blacklists alone to control all network blockages, especially ones that do not require DNS or who use a private DNS or secure DNS. You have no way of knowing what traffic slips past without adding a sniffer. Yet another tool. turns out there is a image for Rpi (4) <a href="https://downloads.openwrt.org/snapshots/targets/brcm2708/bcm2711/">https://downloads.openwrt.org/snapshots/targets/brcm2708/bcm2711/</a> . My Pi is not here, else I would try this image out right now. Anyway, leaving this note here in the blog for later when I can find my raspi.<br />
<br />
My end use case is most commonly an iPhone, which does support Ad blocking in a browser, but I'm not using Safari, so a lot of Google search results show apps that purport to block adds. But they are all just browser plugins. I have no idea why the word Safari barely appears in any of the app title descriptions. Apple app store publisher rules are not slipping I hope.Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com2tag:blogger.com,1999:blog-3033838173445667449.post-23377408260505392832020-02-06T07:08:00.001-08:002020-02-06T07:08:10.191-08:00Test engineer community challenge.So last year 2019 around Spring/summertime, I got a bee in my bonnet about the MOT. The Ministry of Test is a cool community of testers. My "cause" or mission, was being unable to make it to the local chapter meetups <a href="https://www.meetup.com/Ministry-of-Testing-Cambridge">https://www.meetup.com/Ministry-of-Testing-Cambridge</a> . Mainly because work did not allow. So I started getting more active online, slightly. I got myself a cool MOT tee.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3ONTfmTd4AJrhfFhUNB7NZDCglZSlNPEVrrqGkqBVu1AXr0WSPDdHMnP2iuKDXzOSpJ_9_0nAvZipvzxthH5PBaBIt-7a5kYi2xRHt5DEWB3e5uAZu7BNgBsE7vwkhg9LPzaECSh7_p8/s1600/20200206_145543.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3ONTfmTd4AJrhfFhUNB7NZDCglZSlNPEVrrqGkqBVu1AXr0WSPDdHMnP2iuKDXzOSpJ_9_0nAvZipvzxthH5PBaBIt-7a5kYi2xRHt5DEWB3e5uAZu7BNgBsE7vwkhg9LPzaECSh7_p8/s320/20200206_145543.jpg" width="240" /></a></div>
And then kinda kept trying to find time in a busy day, to learn how to test better, and to stay ahead in my job.<br />
Then I hit a rough patch, mid summer in 2019. I quit my job, found something that was more healthy and started building again. It's not easy as you get older, and I guess you deal with your rough patches in your own way. In December I decided to take it very easy in real life, scale it all back. But enough about me, this is about software testing. I'm just the context, the bread around the filling of this sandwich.<br />
<br />
MOT have free to attend webinars that get recorded, you can watch these recordings if you subscribe. Joining at the time is cool though, because you do get to ask questions most of the time. Subscribing is quite dear, but very good for you if you are serious and have the time to get deeper into a really great community. You get access also, to some great video training.<br />
<br />
Link up here : <a href="https://www.ministryoftesting.com/">https://www.ministryoftesting.com/</a> to get started, and once you are signed up to events and so on, finally head down to the club : <a href="https://club.ministryoftesting.com/">https://club.ministryoftesting.com/ </a>Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-14126953055645795032019-11-16T07:34:00.000-08:002019-11-18T13:45:10.745-08:00Music Manager login fails : Google play music sync painsAt the moment i am struggling so much that I have raised a support ticket with google. so not many people know this, but google do actually give support , real humans do try to help you. There are some things they cannot help you with, before I get onto my main issue, here are 2 of the things they cannot do.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIy0SaJai-dQ74WuWh4WZsVoSF21-P0nUqZypkY05w5ELMEshyy37tH-3ya-iTws1NNLGtnn4VxqtREb6rGcYJ8ttdsM22wVMNwnHK2puHAGtSHpNi6m2XW9aRBASO6you-a9HfHB2AR8/s1600/basement.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="252" data-original-width="346" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIy0SaJai-dQ74WuWh4WZsVoSF21-P0nUqZypkY05w5ELMEshyy37tH-3ya-iTws1NNLGtnn4VxqtREb6rGcYJ8ttdsM22wVMNwnHK2puHAGtSHpNi6m2XW9aRBASO6you-a9HfHB2AR8/s320/basement.png" width="320" /></a></div>
1. Give you the keys to the bosses Ferrari for a day. I always ask the phone operator this when they ask "Is there anything else we can help you with?" It always lightens the mood.<br />
2. Google play on mobile cannot upload/add any music tracks that are on your phone SD card/storage to a playlist that is synced in the cloud.<br />
<br />
That last one would be handy, because my support ticket is all about how sync is just broken lately.<br />
<br />
For the last week, I have been unable to add any of my own music to my library, I have used the windows app to upload, but the songs don't show up. I have used the Firefox upload button, same issue. I have found a cool button in the settings screen of the player, which is supposed to refresh, but refresh does nothing. I have a number of screenshots which indicate that something on my computer is wrong, because the Google Music Manager app on Windows (which I have repeatedly updated), appears to baulk. Still not sure why.<br />
<br />
I have now also tried to use the player in a VM on linux, so a clean machine is also unable to connect.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgime1HtNEFDANL8rhLCstIgdyAi6ntFS_jEg_Ng3CHxZCmGniP542Y9g87G2bol8ffdPx-T7Co486dAJQszmsprnglUe-3G5VO79NJdi-OGmbk3ks3eGK8XWHL8NJ27387PFbhAGDh93E/s1600/in+beta.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="521" data-original-width="932" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgime1HtNEFDANL8rhLCstIgdyAi6ntFS_jEg_Ng3CHxZCmGniP542Y9g87G2bol8ffdPx-T7Co486dAJQszmsprnglUe-3G5VO79NJdi-OGmbk3ks3eGK8XWHL8NJ27387PFbhAGDh93E/s320/in+beta.JPG" width="320" /></a></div>
And its unable to log in. The app has a huge networking issue somewhere, it's very intermittent.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi15L0p_qwJofK18fCSwADjjCgtPyOoSXYyQKXVnIb1DpepFIzgNBDPYNzTsrATNtOtt2R8trG9gBrNcD9lR9jhn5wSq_-NqRvla9QN09UhY_FsDtMuUy1lxTspGyDtEa80-IREJGQcDPI/s1600/google+cannot+see+network.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="691" data-original-width="553" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi15L0p_qwJofK18fCSwADjjCgtPyOoSXYyQKXVnIb1DpepFIzgNBDPYNzTsrATNtOtt2R8trG9gBrNcD9lR9jhn5wSq_-NqRvla9QN09UhY_FsDtMuUy1lxTspGyDtEa80-IREJGQcDPI/s320/google+cannot+see+network.JPG" width="256" /></a></div>
So it's not working on windows10, and it's not working on Ubuntu 18 either. I think the fault must be someplace I can get help in? I have even used a remote computer with 1GB internet link to the internet and I see the same problem, so it's not my firewall. I do have more than 1 Google account, and the same thing happens on my other account. So its pretty much a configuration issue somewhere out of my control if you ask me.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiUH01UH3cUTkt-eEf5ByC5z6lfHSVn4P2iP7PO_hhlNbMpe6r_gAV4lpuW68K1FKcwRJqgVD28GR_kZnVl-ifJc7TxSf83TbIMqNBvIcashNouvLutxSlNSxpnoumnjbG-hwvaHrgTzs/s1600/google+app+crashing.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="628" data-original-width="682" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiUH01UH3cUTkt-eEf5ByC5z6lfHSVn4P2iP7PO_hhlNbMpe6r_gAV4lpuW68K1FKcwRJqgVD28GR_kZnVl-ifJc7TxSf83TbIMqNBvIcashNouvLutxSlNSxpnoumnjbG-hwvaHrgTzs/s320/google+app+crashing.JPG" width="320" /></a></div>
Sometimes when I login sucessfully, I get this half-populated form - evidence that it's going a bit pear shaped. I hope to enable some debug logs to at least work out what is going wrong.<br />Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com1tag:blogger.com,1999:blog-3033838173445667449.post-13477758989006256082018-10-10T01:17:00.002-07:002018-10-12T14:05:22.084-07:00nrf52 Feather nRF52832 projectSince I am struggling a little with the Arduino IDE I decided to make some notes to bring things up to date for windows platform use of this target. It's an M4, which might not be covered by the BSPs for some reason. The term BSP means Board Support Package, its a metadata file that the toolchains use to figure out how to generate binaries for the target and what the target is capable of. Stuff like CPU frequency , Flash space, RAM organization and so on.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2WlEa_n_R2V0IMdnsuoyQHbHrSDOMQGktsVlBcA_7mxfEqtbwt1PzmuNIY9uokFqyrN0Rf9ID6VPtMBiFXX9RIYstYnDsjvcNnjpmQUbWHeiPnzAvkK9gbtw-TfHdU4C8RdL7SC4SR04/s1600/20181009_190402.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2WlEa_n_R2V0IMdnsuoyQHbHrSDOMQGktsVlBcA_7mxfEqtbwt1PzmuNIY9uokFqyrN0Rf9ID6VPtMBiFXX9RIYstYnDsjvcNnjpmQUbWHeiPnzAvkK9gbtw-TfHdU4C8RdL7SC4SR04/s320/20181009_190402.jpg" width="240" /></a></div>
<br />
So this target has no external flash, basically the USB interface on the front is a CDC (communication device class) only and not mass storage, so you have to flash via the serial protocol it uses I suspect, there will be some tool to be discovered, probably in Python, that glues into the toolchain to do this.<br />
<br />
To get the IDE to recognise your target you will need the right BSP, I found one on this hookup guide <a href="https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide">https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide</a><br />
<a href="https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide" target="_blank"><br /></a>
File/ Preferences<br />
<img alt="Adding the additional board manager URL" src="https://cdn.sparkfun.com/assets/learn_tutorials/5/4/9/arduino-board-add.png" /><br />
And paste https://raw.githubusercontent.com/sparkfun/Arduino_Boards/nrf5/IDE_Board_Manager/package_sparkfun_index.json<br />
into the box. Then add the board by searching in board manager for nrf52 .<br />
<br />
<h2>
At this point it all fails </h2>
2 reasons, the BSP does not include the target I am using, already had to go of pieste and now am expected to leanr how to parse BSP's as well, so I moved to a thread on Adafruit forums where I am workign through this using a ST-LINK/V2 programmer and SWD - 4 wire debugging (1 really) - so far no success that route either, but at least the STLINK programmer can see the target.<br />
Follow further here : <a href="https://forums.adafruit.com/viewtopic.php?f=53&t=141911">https://forums.adafruit.com/viewtopic.php?f=53&t=141911</a><br />
<br />
Some obligatory pics to show where we are: <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyv_1TFsw_uVoCAZXEiDQ7Rx7T1oqzSLFkOMeDyWU3cgOx312hthXk68iNupB4pURGETvUDl5tDgi9A9ejcjkrv5avxDQ25xtXv8JctwHTuRQ1i6fdmvaWLk4zAkf9X3OxU4AesJbplxo/s1600/20181009_195145.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyv_1TFsw_uVoCAZXEiDQ7Rx7T1oqzSLFkOMeDyWU3cgOx312hthXk68iNupB4pURGETvUDl5tDgi9A9ejcjkrv5avxDQ25xtXv8JctwHTuRQ1i6fdmvaWLk4zAkf9X3OxU4AesJbplxo/s320/20181009_195145.jpg" width="240" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo9z5RxXqTyMIk_y-JM61AFEhPA4KA9ZVqkjr79cmUiOtZKXC35W4v-TjhfSFcOyMEIasvh1fTFo03WD-9r1eGoPCqt2r5VrQJo9hsvXxKkss9-HuwqgRX4WWUQ3XMO-wifHhtMRoue3E/s1600/20181009_195703.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo9z5RxXqTyMIk_y-JM61AFEhPA4KA9ZVqkjr79cmUiOtZKXC35W4v-TjhfSFcOyMEIasvh1fTFo03WD-9r1eGoPCqt2r5VrQJo9hsvXxKkss9-HuwqgRX4WWUQ3XMO-wifHhtMRoue3E/s320/20181009_195703.jpg" width="240" /></a></div>
<h2>
Unbricking options</h2>
Re-program the soft device using nRFStudio apparently... <a href="https://www.nordicsemi.com/eng/nordic/Products/nRFgo-Studio/nRFgo-Studio-Win64/14964">https://www.nordicsemi.com/eng/nordic/Products/nRFgo-Studio/nRFgo-Studio-Win64/14964</a><br />
However when you start doing this, it downgrades your commandline tools for nrf from 9.7 to version 8.5 . I get the impression Studio has been discontinued or is out of support? Anybody's guess, is going to be better informed by me paying more attention from here onward.<br />
<br />Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-55705639559072711322018-10-01T01:26:00.001-07:002018-10-01T01:26:57.510-07:00Thinking of a Career in games development?Here is what you are up against for starters, it's a crowded place, and only the rockstars actually make it.<br />
<img src="https://infinitroid.com/static/images/blog/annual_steam_releases.png" style="-webkit-text-stroke-width: 0px; background-color: transparent; border-bottom-color: rgb(0, 0, 0); border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: rgb(0, 0, 0); border-left-style: none; border-left-width: 0px; border-right-color: rgb(0, 0, 0); border-right-style: none; border-right-width: 0px; border-top-color: rgb(0, 0, 0); border-top-left-radius: 4px; border-top-right-radius: 4px; border-top-style: none; border-top-width: 0px; color: black; font-family: Merriweather,Georgia,serif; font-size-adjust: none; font-size: 17px; font-stretch: 100%; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; line-height: 28px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-width: 730px; orphans: 2; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" /><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br />
<a href="https://infinitroid.com/blog/posts/did_i_just_waste_3_years">https://infinitroid.com/blog/posts/did_i_just_waste_3_years</a><br />
Okay, so you read the link, 3 years of not getting paid at all, still worth it as a learning experience, I mean sure 3 years on and you have got to have learned a lot. You are only employable once you have really made a few mistakes and learned to work independently and become a really valuable asset.<br />
<br />
<h3>
My son</h3>
A bit like me, at that age, all I wanted to do was program and sometimes write games, mainly program useful programs, and maybe games sometimes. Reality sets in after a decade, and you discover that games does not pay, a decade on you are already too old to play that "game". And what will you have learned? Not much. Moving from games development into commercial development is hard, moving the other way is like falling off of a bike in comparison. Very few games have gotten released without an "iron triangle" around the developers neck, a hard deadline. Hard deadlines in commercial dev jobs are much tougher, but they have a life after release, games don't. Last year's game does need maintaining, nobody will fund the maintenance, and besides, the code is probably not maintainable in smaller games. Welcome to the real world, commercial development is as close to the edge as you get these days. What is your experience?Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-75288267391159509622018-06-24T07:23:00.001-07:002018-06-24T07:23:21.665-07:00Crazy shower designAt the moment I have 4 people using an electric showe, that comes to probably 10pence each person, per day, which averages to 3 showers x10 after 3 days, you look at 5 quid in heating. So I have an idea, will update on whether this really ends up working or not.<br />
I have removed all electric cables from this diagram, as well as the heat sources (solar and wood fired) that heat the main boiler.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkeGG8rmYkV0-zKv9AL4oDHHu2NOj2W9FJkp7rqrhyJzYbhfx7k3IBMrHodZEaUfXFiJ4aUo4ck2DOXW3uOM94bMyWaRb2hCUO15lFcxBbpaPh6P5tHksJIsVUBQmlAC6etXG2RlA3M_o/s1600/shower.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="664" height="361" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkeGG8rmYkV0-zKv9AL4oDHHu2NOj2W9FJkp7rqrhyJzYbhfx7k3IBMrHodZEaUfXFiJ4aUo4ck2DOXW3uOM94bMyWaRb2hCUO15lFcxBbpaPh6P5tHksJIsVUBQmlAC6etXG2RlA3M_o/s400/shower.png" width="400" /></a></div>
Looks crazy, but as far I can see nobody in the UK builds this kind of setup, even though the parts are freely available and apparently on their own, quite commonplace. So a bit of a mystery to me.<br />
<br />
If, and if this works well, then I have more ideas for modifying the other parts of the system. but that's for another day.Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com2tag:blogger.com,1999:blog-3033838173445667449.post-13387743246934430382018-05-28T04:41:00.000-07:002018-05-28T04:41:50.479-07:00Homework with VS CodeSome folk have not yet heard of Visual Studio Code<br />
It's a brand new lightweight code editor from Microsoft that can run almost anywhere. And the surprise is it's not chunky and lets you code fast.<br />
<h2>
Homework</h2>
<div>
Up till now I have been learning Python properly, but today it's a job interview C exam question, so python is out, and C is in. Here are the steps.</div>
<div>
1. install VS code</div>
<div>
2. install mingw</div>
<div>
3. install check unit test framework</div>
<div>
4. coffee (or so it was thought...)</div>
<div>
<br /></div>
<div>
If you have not yet, install Visual Studio Code, the download is small and it's totally not the beast Visual Studio is, it has some nice plugins, don't go to town, but the Python plugin is one I do recommend(, although Pycharm <a href="https://www.jetbrains.com/pycharm">https://www.jetbrains.com/pycharm</a> ) is also pretty awesome). Add the C/C++ plugin for now.</div>
<div>
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;">
<div>
<span style="color: #608b4e;">// main.c</span></div>
<br />
<div>
<span style="color: #569cd6;">int</span> <span style="color: #dcdcaa;">main</span>(<span style="color: #569cd6;">void</span>)</div>
<div>
{</div>
<div>
<span style="color: #c586c0;">return</span>(<span style="color: #b5cea8;">0</span>);</div>
<div>
}</div>
</div>
</div>
<div>
Getting this far brings back memories :/</div>
<div>
<br /></div>
<div>
Next up is MinGW-w64. I'm going to focus just on getting it to work with VS code. go to the mingw site, it will point you to MinGW-w64 on sourceforge for the download on Windows.</div>
<div>
I managed to find a pretty good guide, but for my purposes I was missing some of the runes I had not yet learned.</div>
<div>
My build task looks like this</div>
<div>
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;">
<div>
<span style="color: #9cdcfe;">"tasks"</span>: [</div>
<div>
{</div>
<div>
<span style="color: #9cdcfe;">"taskName"</span>: <span style="color: #ce9178;">"build compositer"</span>,</div>
<div>
<span style="color: #9cdcfe;">"type"</span>: <span style="color: #ce9178;">"shell"</span>,</div>
<div>
<span style="color: #9cdcfe;">"command"</span>: <span style="color: #ce9178;">"C:</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">tools</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">mingw-w64</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">mingw64</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">bin</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">g++"</span>,</div>
<div>
<span style="color: #9cdcfe;">"args"</span>: [</div>
<div>
<span style="color: #ce9178;">"-g"</span>, <span style="color: #ce9178;">"${workspaceFolder}</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">compositer</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">main.c"</span>, <span style="color: #ce9178;">"-o"</span>, <span style="color: #ce9178;">"${workspaceFolder}</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">compositer</span><span style="color: #d7ba7d;">\\</span><span style="color: #ce9178;">main.exe"</span></div>
<div>
],</div>
<div>
<span style="color: #9cdcfe;">"problemMatcher"</span>: [</div>
<div>
<span style="color: #ce9178;">"$gcc"</span></div>
<div>
],</div>
<div>
<span style="color: #9cdcfe;">"group"</span>: {</div>
<div>
<span style="color: #9cdcfe;">"kind"</span>: <span style="color: #ce9178;">"build"</span>,</div>
<div>
<span style="color: #9cdcfe;">"isDefault"</span>: <span style="color: #569cd6;">true</span></div>
<div>
}</div>
<div>
}</div>
<div>
]</div>
</div>
</div>
<div>
<br /></div>
<div>
Next we get the test (checking) tool up before writing any code at all even.</div>
<div>
Go to <a href="https://libcheck.github.io/check/">https://libcheck.github.io/check/</a> and find the download link.<br />
<br />
This is where it all fell apart. check uses autotools, which come with cygwin.<br />
cygwin is just a confusing piece of software without an uninstaller. I keep on removing it, forgetting and then installing it an having huge regrets, ad going back to Visual Studio. so the short answer, is that it got frustrating at this point. And I caved in.<br />
<h2>
Rewind. Get Visual Studio Free</h2>
After a morning of struggling, I just used my hotmail login details to go to <a href="https://my.visualstudio.com/?auth_redirect=true">https://my.visualstudio.com/?auth_redirect=true</a> . Then add the free developer pack to your Microsoft account, and viola, you get to download Visual Studio 2017 instead. It's limited, but comes with tool-chain for C/C++ and a debugger that I am familiar with. Just add the plugin or pack you desire, there are a good few, all free. After wasting Saturday morning to get this far, I used the afternoon to progress the job of writing a really tiny program for a job interview test.<br />
<h2>
Sunday night deadline</h2>
I had wasted much of Saturday morning with a old version of Visual Studio 2013 which kept crashing out in the debugger when MSVCR120D.DLL did something it was not"designed" to do. I installed the Microsoft redistributes, many times, but the dll kept on screwing up, but just in the debugger. I think it was heap corruption in my program, but the debugger was not giving me any clues, so it was a relief to have 2017 installed and debugging just peachy. Fixed my pointer management code and made progress - right up until 1am.<br />
<br />
A task that was supposed to take 4-8 hours ended up taking more like 12. I am not the only person who this happens to. But a few lessons.<br />
1. C pointer arithmetic is easy, but remember to cast to a char first.<br />
2. Do not comment your code. It's counter productive when you have to change the code later.<br />
3. TDD is very time consuming, but it lets you continue working, long after you are too tired to code.</div>
Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-30916276297653766352018-05-25T23:34:00.000-07:002018-05-25T23:34:28.224-07:00Rebuild your Windows machine fastYou will need 2 things (3 probably)<br />
1. a flash drive 8Gb minimum<br />
2. another working computer<br />
3. your windows 10 installation key<br />
<br />
In my case I could not find the key, but will share 2 ways to find it. In my case the dead computer simply had a corrupted partition table/boot file (exact verdict pending.) but was readable.<br />
1. Go to https://www.microsoft.com/en-gb/software-download/windows10<br />
Don't choose the options around recovery, you want a download for another machine - choose the media creation tool option. this downloads a 20Mb application , run it, and plug in your flash drive. point it to the flash drive, and it will start downloading. This bit took about 5-10 minutes. Then it starts copying the files, also takes about 10 minutes. During this time, rip the hard drive out o the dead machine and put a shiny one in, and check the bios settings are still looking sane and can see the new disc.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHgfsrS8ww3Cmo5UaYvagpEr2g2secoA-jBUr86CHNvBkujSjUL8yCfZbV9UfMxx5Ze1sp4PAp5-sw7Q0CzzXUQfJjQBjJp7D1mByAJOnRh8fzzjbcTvW2e0KXFZ8_zPvaTTg5HPX6o9s/s1600/20180526_072446.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="756" data-original-width="1008" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHgfsrS8ww3Cmo5UaYvagpEr2g2secoA-jBUr86CHNvBkujSjUL8yCfZbV9UfMxx5Ze1sp4PAp5-sw7Q0CzzXUQfJjQBjJp7D1mByAJOnRh8fzzjbcTvW2e0KXFZ8_zPvaTTg5HPX6o9s/s320/20180526_072446.jpg" width="320" /></a></div>
<br />
2. Boot the computer from the flash drive, and start installing. While this is going on, you want to rescue your data off the dead disc, I used a drive caddy, since the only problem was corruption. In the past I used to plug the bad disc right into a secondary IDE channel on my good machine. But now we are all SATA, so cabling is simpler, but still a major mission to find power. My experience of the faffing with screwing the drive in temporarily so that it does not come to more harm, so the caddy is slower, but less trouble.<br />
<h2>
There are many many ways to do this, this one was fastest</h2>
3. Find your key, this is the good bit.<br />
Go to http://www.nirsoft.net/utils/product_cd_key_viewer.html#DownloadLinks<br />
scroll down and download the 64bit version.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX7nolAdcCZCqtu7LpFV2J5KRIZVrZX1IwhCdZF4YgmkDjtT-ziajzLonGfMoPpQWXWwE-ChU9ZVckM7pfgaunkoxbDLBnAMsAoUorz8_-_yZOHp_Zimq5obvmQGvaZHzlByh1CnhIoxc/s1600/produkey.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="788" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX7nolAdcCZCqtu7LpFV2J5KRIZVrZX1IwhCdZF4YgmkDjtT-ziajzLonGfMoPpQWXWwE-ChU9ZVckM7pfgaunkoxbDLBnAMsAoUorz8_-_yZOHp_Zimq5obvmQGvaZHzlByh1CnhIoxc/s320/produkey.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Run the tool as administrator.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy2Wfs6agObfFvvciJykzN4V30LCNoFeP0WLbQpXjt-BV_z2CCBuLlDz9-UOJtsFzzDRFJpp0ofjSWGNH4h1t9ksqbvsQ2FXyxehnf9VDpw_evz4_jmnS7lRND_nSnUJtW_Tejr43UBQo/s1600/produkey2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="497" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy2Wfs6agObfFvvciJykzN4V30LCNoFeP0WLbQpXjt-BV_z2CCBuLlDz9-UOJtsFzzDRFJpp0ofjSWGNH4h1t9ksqbvsQ2FXyxehnf9VDpw_evz4_jmnS7lRND_nSnUJtW_Tejr43UBQo/s320/produkey2.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Point it at the dead disc, and viola.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLWfTV6ykkdDl58KtOEAbQcDHg9ALX-y8VVmikgOp5ea5QB0Rrhn6OwSFB1wjdXSx-S154Wsxs_uaowDVxHcNHRByR0N2exBH-lHhQGFHoOcvputTuPevdNQWiXvN3217G-Uy72HTwzlM/s1600/produkey3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="851" height="129" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLWfTV6ykkdDl58KtOEAbQcDHg9ALX-y8VVmikgOp5ea5QB0Rrhn6OwSFB1wjdXSx-S154Wsxs_uaowDVxHcNHRByR0N2exBH-lHhQGFHoOcvputTuPevdNQWiXvN3217G-Uy72HTwzlM/s320/produkey3.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Oh, a second way to get your CD key back, is to have written it down someplace, like in a document on google drive, which you forgot you had didn't you?Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com1tag:blogger.com,1999:blog-3033838173445667449.post-44042132489760729152018-05-14T13:23:00.000-07:002018-05-14T13:23:02.274-07:00A Python strangle holdHaving a look at a piece of work I built for client reflectively. I noticed that I had early on opted for a bottom-up approach to an implementation where I control a remote machine.<br />
<h2>
Bottom up is not a design Pattern</h2>
I said to myself that it was wrong to have gone that way about it, because bottom up meant starting from a windows mobile API and then wrapping it in Powershell, and then wrapping that in a Python unittest. In balance it's a bit light on Python which means anyone reading or maintaining needs to learn a lot of Powershell. The powershell scripting is managing a remote connection session across test steps. This balance is a side effect of bottom-up.<br />
<br />
<b>Python script</b> ~ 300 lines<br />
<b>Powershell script</b> > 500 lines<br />
<b>Mobile API</b> ~ 10 lines <= where all the work happens<br />
<br />
If I had written it from top-down and written around 500 lines of Python, it would have shifted the balance but left us with around 200 lines of Powershell and a large performance hit per step in the test because the Python code cannot cache the Mobile API remote session connections. Every test probe or prod, would be a round trip and would need a new connection. My biggest regret is not sticking to my guns and moving more code to the Powershell side because it's easier to manually run pieces of Powershell as scriptlets when manually verifying. You could probably run python functions in the Python console/ide as manual steps too, but I need to stick to my expertise more often in future. Anyway, the Python code balance is annoying because maintainers do have to learn 2 languages. Top down would have been easier to maintain by nature.<br />
<h2>
Strangle Hold</h2>
<div>
I am enjoying the Python learning, which was part of the reason for my bottom-up by starting in Powershell, and learning the Python language all over again in the background while I worked my way up. I could not have commanded the Python well enough to start there I suspect. Quite happy with the outcome in terms of the refreshing of my very stale and super-basic Python. But would do it the other way if I did a similar project again.<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7E8WgdYpa7UsunQ5RQP4UZH7fhE2C7knllQHspQiuE22a7UYnzISfjy2K_SCs86depnjI4VfxJZUNJpvHFSoJssnNUhiqPtc9ziX4aQoZII_PhL0A-0jLHBCuQAYkhy9nABXaCOkm4A/s1600/whip.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="840" data-original-width="1260" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7E8WgdYpa7UsunQ5RQP4UZH7fhE2C7knllQHspQiuE22a7UYnzISfjy2K_SCs86depnjI4VfxJZUNJpvHFSoJssnNUhiqPtc9ziX4aQoZII_PhL0A-0jLHBCuQAYkhy9nABXaCOkm4A/s320/whip.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Wierdest thing is that Python seems to be language lawyer territory in terms of style far more than in terms of looks than for example C code is lawyered over, where performance is 50% of the game. Snakebite on the other hand is 50% of the Python game. By snakebite I mean pretty pythonic code. A lot of time is spent making code look like it is pretty. Python actually has keywords and syntax (above and beyond the indentation rule) to help you make the code pretty. A pity because the excellent pylint tool is actually two tools in one, style and grammar, and because pylint parses the code and the references or lack of usage, which you don't want often. And so I find myself disabling some of the pylint warnings that are not so much about code prettiness, but rather syntactic rules, which should have been totally separated in the debate. I want my code to compile, before I want it to look like it wants to be eaten!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBWbdq43PAtPhU-xzgUlcqguKc80-YgexLyQCU9KqTBZTBH4SwK4KIy6gQXMti0vBGOvRQ9UK4lrXU-Zm_BpNAqEr-kKWs49c5wqU3Ny1u680Ci_7t4lqYrWbEqT4GfAGroKSGZPtDWuQ/s1600/swap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1034" data-original-width="1600" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBWbdq43PAtPhU-xzgUlcqguKc80-YgexLyQCU9KqTBZTBH4SwK4KIy6gQXMti0vBGOvRQ9UK4lrXU-Zm_BpNAqEr-kKWs49c5wqU3Ny1u680Ci_7t4lqYrWbEqT4GfAGroKSGZPtDWuQ/s320/swap.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
</div>
<br />Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-8272123008169561732017-11-23T01:09:00.001-08:002017-11-26T01:02:52.984-08:00ffmpeg animated gif one-liner<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYnMWlHtFu-YS3ryDxTp3NBHNJel87vmgaywnq_JubCO1ygwjs1XrXc_dmL3BvH117u29gbCAp06_m6gTqzsSDRaNq0cL_rLoKVNFa8LAPthqFjTI6ApWwT19zL9buTWcSgkihUHkeEBc/s1600/cbc_T.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="746" data-original-width="808" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYnMWlHtFu-YS3ryDxTp3NBHNJel87vmgaywnq_JubCO1ygwjs1XrXc_dmL3BvH117u29gbCAp06_m6gTqzsSDRaNq0cL_rLoKVNFa8LAPthqFjTI6ApWwT19zL9buTWcSgkihUHkeEBc/s320/cbc_T.gif" width="320" /></a></div>
<br />
Commandline to make a quick demo easy and to just by default make it autoplay in for example facebook. sorry if you have seen this all before, but this blog is my braindump.<br />
<br />
.\bin\ffmpeg.exe -i .\cbc.wmv -b:v 50k -r 2 -y -ss 2.000 -t 11.000 .\cbc_T.gif<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqBSz9rfi8tsmTiVj4z-y3T8xJfcHDZuBg9JO70R8zPzLsXpF9vhrvSvjHjSabj0vtbn4EDY-8-eDJEyoFrHJrOvTzpX1Di1lrhZUWs230duBrmWW4G8RFmbpsoPHuVFcp1wi2Zg2Tuvc/s1600/ffmpeg+animated+gif.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="906" data-original-width="981" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqBSz9rfi8tsmTiVj4z-y3T8xJfcHDZuBg9JO70R8zPzLsXpF9vhrvSvjHjSabj0vtbn4EDY-8-eDJEyoFrHJrOvTzpX1Di1lrhZUWs230duBrmWW4G8RFmbpsoPHuVFcp1wi2Zg2Tuvc/s320/ffmpeg+animated+gif.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
-r 2 = 2 frames per second<br />
-b:v 50k = 50kbits bitrate need to add the k, and need to be specific that the rate is a video rate with :v<br />
The bitrate did not have a significant impact on file size.<br />
-ss = start from<br />
-t = duration to convert<br />
<br />
Hope this helps the next person. note, there are loads of similar blog posts, but had to capture some of the more salient parameters, because ffmpeg command parser often just ignores a parameter it cannot parse, so beware typos.<br />
<br />
<h2>
Joining clips</h2>
To join 2 clips -is a bit problematic in windows because the ffmpeg separator | character has a special meaning in dos, so I found the easiest was to create a response file.<br />
<br />
file y:\20171122_173829.mp4<br />
file y:\20171122_170515.mp4<br />
file y:\20171122_173829.mp4<br />
<br />
<br />
Save this text as files.txt (note that this file expects the path separator "/" not "\" , for some reason the [drive:\] protocol is fine with a "\", but paths must use a "/".<br />
<br />
and then use the concat argument<br />
<br />
C:\Tools\ffmpeg\bin>ffmpeg.exe -f concat -i .\files.txt -an -c copy -y .\20171122_173829all.mp4<br />
<br />
notice use of -an to kill the audio track off<br />
<br />
<h2>
Add Audio</h2>
<b>Lastly,</b> to add and use an audio track using <b>-shortest</b><br />
ffmpeg.exe -i .\20171122_173829all.mp4 -i elevatormusak.mp3 -c copy<code> </code>-shortest -y .\20171122_173829final.mp4Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-10519353230017074192017-11-01T08:24:00.003-07:002017-11-01T08:24:47.603-07:00ffmpeg file compressI really easy trick to shrinking files by reducing them from 30fps to 10fps<br />
<br />
..\bin\ffmpeg.exe -i .\largerfile.mp4 -r 10 -y .\destination.mp4<br />
<br />
I'm getting about 20x reduction in filesize - and resulting vidoe is very "skippy", but fine for desktop shared recordings that don't animate.Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-24206717622683510552017-10-23T04:14:00.002-07:002020-03-11T15:02:35.009-07:00Which Test Cases to AutomateI've decided to blog a bit about my day-job, well, my career and passion really. Software testing, but the kind that makes sense, automated regression. But first and foremost a warning, <b>when a computer validates some software, that's not called testing at all</b>, it's called checking. See here for a <a href="http://www.developsense.com/blog/2014/04/in-the-real-world/" target="_blank">bit more on why</a>.<br />
<br />
With that out of the way, lets move on. Automating anything is expensive, automating a test case is not a silver bullet, because a computer cannot validate things like a UI layout making sense, or even an API function call rejecting a parameter value either for that matter. Sure we get frameworks that test for UI changes in web pages and in WPF and other forms based applications. But when controls move and we all know that a UI changes cosmetically very often, that incurs maintenance cost. Tools exist to reduce that cost , but they only do so in very specific ways.<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgflip.com/1xesr4.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://i.imgflip.com/1xesr4.jpg" style="cursor: move;" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Likewise for Automation or Test tooling against public APIs. "Apps" on the internet are the main case here, but this also applies to locally consumed API's not just the web, and all the new kinds of web services available today, its a crazy farm almost. Just about everyone has a web service these days, or at least an API; and since that surface is the really high value customer interface, it's the best place to do testing and best place to automate at the same time. A test script using an API cannot just validate assertions in your test spec, without some skill in writing that script to be maintainable or scale well. Without going into design stasis, arguments about specs, or test frameworks, let's be really Agile; do the parts of the job we can get most early value from first and foremost.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
But which test cases do you convert? From that huge batch of analysis done when you looked at this from a manual test perspective last year. The boss wants you to automate all of the things. Now.</div>
<div class="separator" style="clear: both; text-align: left;">
Based on my inputs and the way we started doing this, one of the grads came up with using Excel. I'll link the sheet below, but first I'll explain what all of the columns mean.</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<table border="1">
<tbody>
<tr>
<td>Test ID</td>
<td>A unique test identifier (optional) A pretty basic thing, but very much dependant on your test management tool choices.</td>
</tr>
<tr>
<td>Name</td>
<td>Description of the test - short is better</td>
</tr>
<tr>
<td>Easy to script</td>
<td>How easy is it to write a test script for this case. Be pragmatic in your estimate. Give it a 5 if it's trivial , but if it's impossible to, give a 0 (zero)</td>
</tr>
<tr>
<td>Manual time cost</td>
<td>The amount of interactive human being time it takes to run this test manually, if the test suite has got lots of setup required, count that time separately, only count time for this test in hours needed. If tests tend to take a few seconds to run manually, adjust this accordingly so that quick tests get a 1 and painfully long to run tests get a 5. Also do not count waiting time, if for a file to copy that perhaps takes 30 minutes, that time is not counted.</td>
</tr>
<tr>
<td>Data/Table driven</td>
<td>Is this a test that really benefits from boundary testing and has multiple simple input output classes that take time to cover most of the meaningful combinations fully if done manually. If Yes, give it a 5 , not really, give it a 1.</td>
</tr>
<tr>
<td>Cost of Failure</td>
<td>Will it hurt the product and crate risk if this test fails. If Yes, give it a 5 , not really, give it a 1.</td>
</tr>
<tr>
<td>Likely to regress</td>
<td>Is this case likely to catch useful regressions caused by code or integration changes? If Yes, give it a 5 , not really, give it a 1.</td>
</tr>
<tr>
<td>ReUse</td>
<td>Is automating this a test now, going to help you write other tests by providing a library of helper functions that will grow your coverage eventually? If Yes, give it a 5 , not really, give it a 1.</td>
</tr>
<tr>
<td>Priority</td>
<td>Does this verify anything a manual tester would have to do anyway before most other testing commences. Do testers test this functionality very often? In other words, is this a test that has to run early in the cycle. If Yes, give it a 5 , not really, give it a 1.</td>
</tr>
</tbody>
</table>
<div class="separator" style="clear: both; text-align: left;">
Some things to notice here, I use a very low resolution scale of 1-5. Higher granularity in the question scales actually end up take much longer on average for a user to guess at a value, and let's face it, this is a game of educated guesses or estimates anyway. It's best if 2 people do this process together. Some of the columns only benefit from entering a 1 or a 5 and nothing in between, some of the columns even allow a 0. As a tester, I'd not expect you not to try entering a 0 in cases where it makes sense to, for these, the sheet will give still you a good answer out. So you can just add these all up, or give each question priorities. In another posting, I'll share the spreadsheet template and the weightings as well.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This only works well after you have obviously captured half a dozen cases and looked at them in relation. Remember, don't spend too much time on each row, this is a planning activity only.</div>
Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0tag:blogger.com,1999:blog-3033838173445667449.post-19548190333598000372017-09-27T04:39:00.000-07:002017-09-27T04:45:56.969-07:00Lean Coffee MeetupA "Lean Coffee" under the Meetup banner is an agile interpretation of a networking event for software testing professionals in our case. Because time is precious the monthly morning coffee is a very intense and quick-fire format. Final moments close with a summary where everyone states one thing they learned. Results here may vary, and I made notes only for our table which was half of the 12 or 13 odd who attended. A voted Q&A format with 8 minutes per topic presented the following ideas.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizmsoVpke7gfC6ZiDDcsqVTTuORfGw-_LE6uFCP290rzRc0uMjaFIAWqgZEdRyKAXXJyW8V1QXhlVSMrbs_uP7lPP38JIJfxQiT9pLATVXG0rYo7drAj3x5Q1tfKu5BQccSpRaO3Tk9mM/s1600/20170927_090256.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizmsoVpke7gfC6ZiDDcsqVTTuORfGw-_LE6uFCP290rzRc0uMjaFIAWqgZEdRyKAXXJyW8V1QXhlVSMrbs_uP7lPP38JIJfxQiT9pLATVXG0rYo7drAj3x5Q1tfKu5BQccSpRaO3Tk9mM/s400/20170927_090256.jpg" width="400" /></a></div>
<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; margin-bottom: 16px; padding: 0px;">
</div>
<ul>
<li>How to develop new testers. Getting up to speed suggestions. </li>
</ul>
(Test mentoring, timeboxing, domain learning and process learning discussed)<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; margin-bottom: 16px; padding: 0px;">
</div>
<ul>
<li>Is the programming language used to write automated tests important?</li>
</ul>
(pros and cons for Java,Ruby,Python and importance of test fixtures were covered. As well as scale-ability and performance)<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; margin-bottom: 16px; padding: 0px;">
</div>
<ul>
<li>In a one man test team, how do you plan?</li>
</ul>
(3 amigos, division of responsibility, assesment of the security risk, assesment of scale risk)<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; margin-bottom: 16px; padding: 0px;">
</div>
<ul>
<li>How to get others to see your side of a test failure?</li>
</ul>
(describe the risk to business and cost clearly)<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; padding: 0px;">
</div>
<ul>
<li>Biggest challenge in test </li>
</ul>
(horror stories ensued)<br />
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; padding: 0px;">
<br /></div>
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; padding: 0px;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/ahY0_s2WFSg/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/ahY0_s2WFSg?feature=player_embedded" width="320"></iframe></div>
<div style="animation-delay: 0.1s; animation-duration: 0.1s; animation-iteration-count: 1; animation-name: fontfix; animation-timing-function: linear; background-color: white; color: rgba(0, 0, 0, 0.87); font-family: "Graphik Meetup", helvetica, arial, sans-serif; font-size: 16px; padding: 0px;">
In the meet I mentioned a link to this clip to share with people<br />
<br />
If you want to join up with us, please follow this link and sign up. <a href="https://www.meetup.com/Ministry-of-Testing-Cambridge/events/243456138/?rv=cr1&_af=event&_af_eid=243456138&https=on">https://www.meetup.com/Ministry-of-Testing-Cambridge/events/243456138/?rv=cr1&_af=event&_af_eid=243456138&https=on</a></div>
Conrad Braamhttp://www.blogger.com/profile/14516128061510018135noreply@blogger.com0