Category Archives: Computer Science

Writing Great Test Cases and Becoming a Great Software Tester

I completely agree with Kyle McMeekin when he states in a blog post titled “5 Manual Test Case Writing Hacks,” from April 11th, 2016, that it should come as no surprise that great software testers should have an eye for detail. What may not be as obvious, however, is that great software testers should be able to write great and effective test cases. McMeekin goes on to observe that writing effective test cases requires both talent and experience. In an attempt to begin my journey to become a great software tester, I decided that I should pay close attention to the advice offered by experienced testers as they reflect on the skills they have gained from their time in the industry. Hopefully, by following the tips of more experienced testers, I too will someday be able to contribute to highly valuable test cases the improve productivity and help to create high quality software.

The first step to writing great test cases is knowing what components make up the test case. While many of the components were obvious to me, there were others that I had not thought of. The test steps, for example, are important because the person performing the test may not be the same person who wrote the test. Knowing how the test should be performed is important to obtaining a valuable result from the test.

What I found most valuable about McMeekin’s post, however, were his tips on how to “write better test cases that will lead to better quality software for your company.” His first piece of advice is to keep test cases simple. They should be in simple language, and follow the company’s template. Although not specifically mentioned in this guide, I remember reading that if a test case seems to become too complex, you should begin considering breaking it up into smaller pieces. Second, McMeekin recommends making test cases reusable. Taking into consideration that your test cases could be adapted to other scenarios or reused in another application should help to develop test cases that are reusable. Third, McMeekin suggests placing yourself in the shoes of the tester or developer rather than the test-case writer, and being your own critic. Considering what parts of your test-case may be ambiguous or frustrating for others using them will often help to create better tests. This goes hand in hand with the fourth recommendation, which is to think about the end user. Understanding the expectations and desires of the end user will certainly help to create test cases that lead to better, more successful software. The last recommendation that McMeekin gives is to stay organized. This suggestion could apply just about anywhere, but with hundreds or possibly even thousands of potential test cases, staying organized is certainly essential to being a great tester.

Although I am sure there is a great deal more to consider in my quest to one day become a great software tester, I think that keeping these things in mind will certainly improve the quality of the test cases that I write. In the rapidly advancing field of computer science, I don’t feel that I will ever stop learning new and improved ways of doing things or further developing my skills.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Thoughts on the Angular Material Datepicker

While researching how to make the dreams of developing a countdown clock Angular application for the final project of Software Construction, Design, and Architecture, I came across an interesting writeup on the Angular Material Datepicker by one of the Angular Material developers, Miles Malerba. With plans of creating a user-inputted countdown timer, a datepicker component sounded like welcome alternative to making one from scratch. I decided to look further into the Material Datepicker to see if it would be something that could prove useful.

The Material Datepicker includes support for the required attribute, which is used for data validation when a form is submitted. This seems like a worthwhile feature, as it would make little sense to allow the user to create a countdown timer without inputting a date to countdown to. The datepicker also has an additional mdDatepickerFilter attribute, which allows for “finer grained control of what’s considered a valid date.” This also seems like an important feature for a countdown timer input, as I would want to disallow users from selected a date in the past, as this would be invalid to count down to.

While I had not previously thought about supporting mobile users with my countdown timer application, the Material Datepicker’s mention of a specific “touch UI mode” made me reconsider. I think that a countdown timer that is tailored mobile users would be an important audience to appeal to. Perhaps mobile users would have more use for a countdown timer on their phones than on the computer. I will have to look into the possibility of supporting mobile users.

While it does not apply to my project, I thought that the Material Datepicker’s DateAdapter and support for any locale was an interesting addition. The DateAdapter is an abstract class that allows developers to specify the formatting of dates, which allows for representations of 1/2/2017 to mean January 2nd, 2017 in America and February 1st, 2017 just about anywhere else. Since my project will only need to include support for the American date representation, the included NativeDateAdapter class should fill my needs. This class uses the Javascript Date to represent dates, which is the American version mentioned earlier.

In conclusion, I think that Angular Material Datepicker will certainly help in the development of my Angular Countdown Timer Single Page Application (SPA). Having a datepicker component that is already written will allow me to focus on the more important aspects of design, such as allowing users to save their countdown timers by implementing database calls. While there is certainly still much work to be done on my Angular SPA, reading about the Angular Material Datepicker has me excited to get started developing.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

How to Effectively Discuss Software Testing

It is not easy to come up with a definition that truly encompasses all that the discipline of software testing entails. From writing test cases to performing automated testing, what a particular software tester does can vary greatly. It is not surprising then, that there often misconceptions surrounding discussions of software testing. Reading a post titled “Six Things That Go Wrong With Discussions About Testing” by James Bach on his blog gave me insight into some of the things that I should avoid when talking about testing.

The first point that Bach brings up is that the number of test cases that you have written does not matter. To anyone who has ever written a test case, this is a pretty obvious one. You could write a million test cases that all do the same thing, but if you’re not exercising the code in unique and possibly unexpected way, then you are wasting your time. Any tester who brags about the number of test cases that he or she has written is clearly missing some critical understanding of the purpose of testing software.

Secondly, Bach states that each test should be thought of as an event rather than as an object. Whether it is done automatically or manually, tests must be performed, they do not simply exist. This is why software testers will never be replaced by computers or algorithms. Each time a tester performs a test, it produces a unique and meaningful result. This ties in with Bach’s fourth point, which is that even in the case of automated testing, humans are responsible for the successes or failures of the tests being run. Computers are unable to think critically about problems like humans can, and they can only go so far as to check simple facts, not effectively test software.

Backtracking to Bach’s third point, testers should always be able to describe their testing strategy, even as it evolves over the course of testing. Understanding how and why a given test is being performed allows testers to think about things such as how to improve the test, what tests need to be developed next, and how to develop better tests more quickly in the future.

The fifth topic that Bach discusses is how people “talk as if there is only one kind of test coverage”. As a student currently learning about the types of testing coverage, this one came as a bit of a surprise to me. I imagine that testers who fall victim to this fallacy of testing never received formal education in software testing or have become so set in a single way of testing that they are failing to see the bigger picture.

Lastly, Bach discusses testing as an exploratory learning task rather than as some scripted, monotonous procedure. Again, I think that my current enrollment in a software testing course leaves me a bit biased on this point. Nearly every test that I write is a learning experience for me, and I certainly do not feel that testing is a static task.

While I can certainly see where Bach is coming from with all six of his “Things That Go Wrong With Discussions About Testing,” I am pleased to know that the my understanding of software testing does not fall into any of his categories for the most part. I feel that many of these things apply to testers who may have been self-taught or had minimal theoretical training. I think that my education certainly helps me to see the big picture of why software testing is so essential, rather than just going through the motions of writing test cases for the sake of it.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Practical Uses for Design Patterns

Sometimes completing assignments can become monotonous. I think that I find this mainly happens when I cannot seem to think of a practical use for what I am currently working on. While I understand that many of the example implementations of design patterns are intentionally left abstract so as to highlight the importance of the pattern rather than the complexities of the underlying system, this bores me. My approach to programming is often utilitarian in the sense that I want to know how what I am currently working on is going to make someone’s life easier.

(Image source: https://drquicklook.com/products/usb-to-sd-card-adapter)

This week I listened to Episode 30 of the Coding Blocks podcast, from July 26, 2015. In the episode, Allen, Joe, and Michael discuss the Adapter, Facade, and Memento design patterns. The first pattern that was discussed was the Adapter pattern. I paid particularly close attention to this pattern, as I will be researching and compiling an informative piece on the Adapter pattern in the coming weeks. The podcast provided a link to an excellent tutorial on TutorialsPoint, which I will most definitely be using as a reference for my project research. The real-life example used to describe the Adapter design pattern was that of the SD-card adapter, which takes the SD card and adapts, through the use of an interface, to a USB cable that the computer can recognize and use. The Adapter design pattern implemented in software provides a very similar function by taking two otherwise incompatible interfaces and acting as a bridge between them so that they may seamlessly interact with one another.

In the discussion of the Facade design pattern, I saw some parallels to the Adapter pattern but there were certainly also observable differences. The Facade patterns aims to hide the complexities of some underlying system by providing a simplified interface through which the user can gain access and use the resources provided by the system. The example that the three discuss that I found very interesting was transactional payment processing systems such as PayPal. The goal of applying Facade in this case would be to hide multiple repeated calls to APIs that must be completed each time a user would like to perform a task such as setting up a secure connection, passing a token, storing a token, etc. before actually accomplishing the desired task.

The final pattern that is discussed is the Memento design pattern. While the three seem to have mixed feelings about the usefulness of the Memento pattern, I thought that the discussions regarding Megaman and System Restore’s implementation of this pattern were extremely useful and interesting examples. The pattern, in a basic sense, aims to save a complete copy of the state of the object at any given time. This state object is accessed and maintained by two classes – a caretaker and an originator.

What I like most about the examples and explanations that the three give for their respective design patterns is how practical they seem. While the ultimate goal of applying a design pattern to a particular problem is to simplify the overall implementation, it is certainly not always a simple task to apply a pattern. Understanding some of the motivation behind why applying the design patterns makes an implementation cleaner and more effective satisfies my utilitarian inclinations. I am looking forward to exploring the complexities of the Adapter pattern more thoroughly in the near future.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Effective Data Migration Testing

When considering the term software quality assurance and testing, what comes to mind? For me, I think of developing test cases that exercise program functionality and aim to expose flaws in the implementation. In my mind, this type of testing comes mainly before a piece of software is released, and often occurs alongside development. After the product is released, the goals and focus of software quality assurance and testing change.

My views were challenged, however, when I recently came across an interesting new take on software testing. The post by Nandini and Gayathri titled “Data Migration Testing Tutorial: A Complete Guide” provides helpful advice and a process to follow when testing the migration of data. These experienced testers draw on their experiences to point out specific places in the migration of software where errors are likely to occur, and effective methods of exposing these flaws before they impact end-users and the reputation of the company.

The main point that Nandini and Gayathri stress is that there are three phases of testing in data migration. The first phase of testing is pre-migration testing, which occurs, as the name would suggest, before migration occurs. In this phase, the legacy state of the data is observed and provides a baseline to which the new system can than be compared to. During this phase, differences between the legacy application and the new application are also noted. Methods of dealing with these differences in implementation are developed and implemented, to ensure a smooth transmission of data.

The second phase is the migration testing phase, where a migration guide is followed to ensure that all of the necessary tasks are performed in order to accurately migrate the data from the legacy application to the new application. The first step of the phase is to create a backup of the data, which can be relied upon in case of disaster as a rollback point. Also during this phase metrics including downtime, migration time, time to complete n transfers, and other relevant information are recorded to later evaluate the success of the migration.

The final phase of data migration testing occurs post-migration. During this phase, many of the tests that are used can be automated in nature. These tests compare the data from the legacy application to the data in the new application, and alerts testers to any abnormalities or inconsistencies in the data. The tutorial lists 24 categories of post-migration tests that should be completed satisfactorily in order to say that migration was successful.

Reading this tutorial on data migration testing has certainly changed my views on what testing means. The actual definition seems much broader than what I would had thought in the past. Seeing testing from the perspective of migrating applications gave me insight on the capabilities of and responsibilities placed on software testers. If something in the migration does not go according to plan, it may be easy to place blame on the testers for not considering that case. I enjoyed reading about software testing from this new perspective and learning some of the most important things to consider when performing data migration testing.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

The Dangers of Relying on Automated Testing

After listening to Jean Ann Harrison’s discussion about how important critical thinking is in the context of software testing and quality assurance on an episode of Test Talks, I wrote a post about The Limits of Automated Testing. Although Harrison’s explanation was great, I had a few remaining questions and this week chose to look for more information on automated testing. I came across a post by Martin Jansson from March 2017 titled Implication of emphasis on automation in CI, and it seemed to provide me with the more comprehensive view of testing automation that I was looking for.

Jansson starts out on a positive note, stating that he “less frequently see[s] the argumentation that testing is not needed.” To me it is almost comical to think about someone arguing that testing is unnecessary. While I completely understand that managers and executives are enticed by the possibility of saving time and money by not testing software, this is an extremely risky and careless method of creating a product. I doubt that anyone releasing untested software lasts very long or makes any money in the industry.

So if not testing at all is not an option, what are the options? Going with the bare-minimum for testing would be running only automated tests, a method that Jansson says is actually used. I have to agree with Jansson, however, when he says that this is not testing, rather it is simply checking. Instead of exploring parts of the code that are likely to contain bugs, you will simply be checking acceptance criteria. By not exploring the code fully, you are failing to find anything that might be outside the scope of the specification or the requirements. I feel that the following graphic provides an excellent representation of how few tests are actually performed when following a testing strategy that relies solely on automation.

(Source: http://thetesteye.com/blog/2017/03/implication-of-emphasis-on-automation-in-ci/)

What constitutes the perfect blending of automated and manual testing may be impossible to know. What is certain, however, is that automated testing cannot be relied upon as the sole method for testing. Jansson puts it in layman’s terms when he says that “you rarely automate serendipity.” Just as Jean Ann Harrison points out in the Test Talks podcast mentioned earlier, automation is not and will never be a replacement for thought. It is a bit of a relief to know that the software development companies are maturing and beginning to understand the importance of having testers who use a combination of automated and manual testing. As long as there continues to be humans writing code, there will need to be humans who test that code.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.

Predictive Applications and the ‘Datafication’ of Everything

We live in a world where we are constantly being bombarded with information. Not only do we consume insane amounts of data, we are also providing other people and businesses with information about ourselves. Signing up for online mailing lists, ordering magazine subscriptions, and even making dinner reservations, information about our habits and preferences is constantly being left behind, a concept that Charlie Berger refers to as data exhaust in a podcast from October 10, 2017 on Software Engineering Radio. The larger concept that he is describing is what is known as ‘datafication’, a buzz-word in the data science and big data spheres that refers to the collecting and storing information about social actions that can be used to perform predictive analyses and targeted marketing.

Specific to the computer science discipline, datafication has implications on the development of predictive applications. In the podcast episode, Berger presents the simple yet extremely effective example of an ATM machine as lacking in the predictive application sense. Berger wonders why each time that he uses the ATM he is asked which language he would like to use, and why such preferences are not somehow tracked and stored, making for a more seamless and personalized ATM experience. Berger even suggests that the ATM track more than language preferences, offering withdrawal suggestions based on previous transaction data from a similar day of the week or time of the day.

While it may not be terribly inconvenient to have to choose a language each time you use the ATM, the concept of predictive applications and the advantages associated with creating and using these types of applications becomes much more apparent when considering larger-scale operations. Retailers can use predictive applications to make important decisions about things like advertising and merchandising. Berger mentions the well-known “parable of the beer and diapers,” where an interesting and entirely unexpected correlation was found between purchases of diapers and beer. While some versions of the tale include the retailer moving the two correlated items next to one another in order to drive increases in sales, this may or may not be factual. Regardless, such examples of generating useful information based on querying data is a perfect example of the power the predictive applications have.

Berger repeatedly stresses the importance of moving the algorithm to the data, not vice-versa. By moving the algorithm to the data, we avoid all of the dangers of bypassing security and encryption. Developing applications that perform queries and compile information that is usable and useful to not only data scientists, but normal people as well, is a perfect example of how machine learning and predictive applications can make everyones jobs easier.

As a student, I took one of Berger’s closing remarks under careful consideration. Berger states that it is much easier for a programmer to learn how to make a program that interprets data than for a data scientist to translate his specific, one-off analyses into programs. With a newfound understanding of why predictive applications are so important to our data-obsessed society, I look forward to exploring how I can begin developing applications that take advantage of machine learning.

From the blog CS@Worcester – ~/GeorgeMatthew/etc by gmatthew and used with permission of the author. All other rights reserved by the author.