Unit Testing: Principles of Good Tests

This week’s post is yet again about unit testing, but this time focuses on a much more broad question. After spending the past two posts trying to determine exactly what unit test and the variety of patterns available it is only natural that this next post focuses on how to write the tests well. As someone who personally has not written many, I can acknowledge that there may be some best practices I am not aware. Thus for this week’s post I am going to discuss another blog post, this one by Sergey Kolodiy, that goes into how to write a good unit test.


So how do you write a good unit test? Conveniently enough Sergey has compiled some principles, which are that the tests be easy to write, readable, reliable, fast, and truly unit, not integration. Easy to write and readable are pretty straightforward, and go hand in hand, as both just mean the tests should be easy to implement to cover lots of different cases and the output of the tests should easily identify problems. As for being reliable this means the tests must be giving the correct output, in addition to actually detecting bugs rather than just passing. Sergey also brings up a good reason for keeping the tests fast, being that lazy developers might skip the tests if they take too long. Finally there is the truly unit, not integration principle, which sounds more complex than it is. This simply means that the unit test and system should not access any external data or resources, such as a database or network, which will ensure that the code itself is working. Sergey chooses to focus on another very important part of writing good unit tests after this.

The rest of this blog revolves around discussing writing testable code as a good unit testing principle. He states a plethora of examples to show some bad practices, such as using non-deterministic factors. To clarify, this means some variable in a method that can have different values every time it is run; the example he uses helps  put this into perspective more effectively. The original purpose of this post was simply to discuss writing the tests themselves, so I do not want to stray too much. I just wanted to mention this part, as it is interesting! If you want to learn more check out the link below.

Source:

https://www.toptal.com/qa/how-to-write-testable-code-and-why-it-matters

From the blog CS@Worcester – My Bizarre Coding Adventures by Michael Mendes and used with permission of the author. All other rights reserved by the author.

Grey Box Testing

Black and white box testing are the testing methods you usually hear about, but what is grey box testing? You probably have done a sort of grey box testing multiple times before learning other structured testing methods. While in black box testing the code structure is known and in white box testing the structure is unknown, in grey box testing, the structure is partially known. Grey box testing is sort of a combination of both black and white box testing. For example, when testing a drop down menu in a UI that your are creating, you can test the drop down on the application then change its internal code and try again. This allows you to test both sides of the application, its representation and its code structure. This is primarily used for integration testing.

The main advantages of using grey box testing include that it combines the pros of both black and white box testing while eliminating many of the negatives for each, you get the testing and feedback from both the developers and testers creating a more solid application, and makes the testing process quicker than just testing one at a time. The saved time from this also allows more time for developers to fix these issues. Lastly, it lets you test the application from both the developers and the users point of view. Some negatives of grey box testing are that there is usually only partial access to the code so you do not have full code coverage of what you are testing and also lacks in defect identification.

Grey box testing does not mean that the tester must have access to the source code, but that they have information on the algorithms, structure, and high level descriptions of the program. Techniques for grey box testing include matrix testing – states status report of project, regression testing – rerunning of the test cases once changes are made, orthogonal array testing, and pattern testing – verifying architecture and design. Grey box testing is highly suitable for GUI, functional testing, security assessment, and web services/applications. Grey box testing is especially good for web services with their distributed nature.

Sources:

Gray box testing. (2021, January 31). Retrieved April 02, 2021, from https://en.wikipedia.org/wiki/Gray_box_testing

What is grey box testing? Techniques, example. (n.d.). Retrieved April 02, 2021, from https://www.guru99.com/grey-box-testing.html

From the blog CS@Worcester – Austins CS Site by Austin Engel and used with permission of the author. All other rights reserved by the author.

Sustainable Motivations – Apprenticeship Pattern

What this apprenticeship dives deep into is that along your journey of becoming a software craftsman, there will be many times you face trials and tribulations. There will be instances where you are burdened with working on a complex project and forced to solve problems you have no idea where to even start. I am sure most of us on our journeys have faced this pressure and this feeling of whether this is all worth doing or whether we are cut out for it. However, this pattern says that we need to have clear and strong motivations when these trials come to our front door. Many people have different motivations as well as altering goals and ambitions. We are all developing software and programming for various reasons as clearly defining these things help us moving forward. We wouldn’t have made it this far if it wasn’t for some motivation that kept us going.

I think this chapter is very relevant for all of us who are trying to become software engineers and architects, and to understand that this journey isn’t just some smooth sailing. There will be times where everything feels easy and you feel lucky to even be in these circumstances. However, there will be other times that bring either the best or worst out of us when we face hard problems related to programming which can mess with us mentally. As a result of this pressure, we need to keep our road and ambition clear on where we want to be heading. Our journey is unique but to keep the journey going we need some strong interior purpose and motivation to pick up our head and keep moving forward on those days when we feel like there is no purpose for doing this. It is at these times, our mind is fogged up with the current problem and not on the bigger picture as to why we are doing all this in the first place. To clear up that fog we need sustainable motivations to be our anchor and help us get through and keep the boat moving. Overall, software architects will need to develop the mindset of believing in themselves and know they are doing what is right for them if they have a clear vision.

From the blog CS@Worcester – Roller Coaster Coding Journey by fbaig34 and used with permission of the author. All other rights reserved by the author.

Building A Reading List

Photo by Skylar Kang on Pexels.com

There is more information available today than ever before, largely thanks to the advent of the internet and the ease with which that information can now be accessed as a result. Because of this increase in available information, the choices can often seem daunting when attempting to choose any source in particular. Especially when searching out books to look into regarding a specific topic, the sheer variety and number of options on even very niche topics makes it hard to make a decision on any one of them to study from.

Concerning the problem I just described, the pattern discussed in section 6 of of Apprenticeship Patterns, Reading List, outlines a useful technique for organizing the seemingly endless collection of books and reading which accumulates when studying a topic. The general idea is to keep a literal reading list, with all of the books (or other sources) you plan to read, reference, or look into recorded for the future. While the text seems to approach this from the context of physical books, I see no reason why this wouldn’t apply to any sort of reference, manual, or other self-educational materials in practice.

Additionally, the authors of Apprenticeship Patterns recommend maintaining the list as a priority queue, in that more important books or references will be studied first, before continuing down the list in order of importance. This seems like a good idea as it makes it easier to prioritize learning things in a more efficient order; subjects or topics which are less important would naturally proceed to rank lower and lower on the list and might eventually be removed if they stay towards the bottom for too long.

This process of removing dead-ends and passed topics of interest would keep the reading list relevant in the long term and help to maintain cohesion (it seems likely that irrelevant topics or sources would naturally begin to rank lower on the list, organically moving them out of the list over time).

Very probably in the near future, I will begin my own reading list, keeping track of prospective sources of information and reference which I feel will be interesting or useful to study. Considering the relative ease of implementing this pattern (keep a list), I would say that it is an easy way to optimize learning or research regarding any topic, but in the context of software development it seems even more relevant still. As there are oftentimes many disparate syntax manuals, tutorials, and textbooks to learn from which could benefit from the concrete organization afforded by a reading list.

Text Referenced: Apprenticeship Patterns, Guidance for the Aspiring Software Craftsman (https://learning.oreilly.com/library/view/Apprenticeship+Patterns/9780596806842/ch06.html#reading_list)

From the blog CS@Worcester – CodeRoad by toomeymatt1515 and used with permission of the author. All other rights reserved by the author.

Unit Testing: What Types to Use

Now that we have a good base understanding of unit tests we can dive a little deeper into the subject. When reading through the previous blog I saw mentions of different types of unit tests and my interest was piqued. From past examples I had seen, I assumed all of these tests followed the same format. Thus for this week’s post I wanted to discuss the different types of unit tests, as I only just learned that there were multiple. To aid in this I found a blog post from a programmer named Jonathan Turner who clarifies what each type is.


This blog post identifies three major types of unit tests, these being arrange-act-assert, one act, many assertions and finally test cases. The arrange-act-assert format is the more traditional method of unit testing and the one that most people are probably familiar with. This format involves setting up the conditions for the test, running the code with the test conditions, and subsequently examining the results of the test. As for the one act, many assertions pattern it uses the same basic setup as the previous pattern, but differs in having multiple assertions about the code at the end of the test. Finally there is the test cases patterns, which takes a different approach than the other two by using a collection of many inputs to check their respective outputs. Now that we understand what each of these patterns are we can discuss their advantages.

Each of these tests have their own use cases where they will be most efficient. The arrange-act-assert pattern is the traditional method and, thus, the most straightforward to implement. This pattern should mostly be used for testing specific conditions or situations of a certain system. The one act, many assertions pattern is best used when you have code that has different sections that each act independent of each other. To clarify, use this if testing a method that has multiple blocks of code that do not affect each other, but must each be validated. Finally, the test cases method is very advantageous if you have a program that has a wide span of input output values. This could be one implementing an algorithm that converts values; the blog post gives a very good example. I hope that this post gave you a glimpse into the variety of unit tests available and would recommend checking out the blog post by Jonathan Turner for further information.

Source:

https://www.pluralsight.com/tech-blog/different-types-of-unit-tests/

From the blog CS@Worcester – My Bizarre Coding Adventures by Michael Mendes and used with permission of the author. All other rights reserved by the author.

Sprint 1 Retrospective

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/new-sample-project

This is our example repository that contains everything we worked on for Sprint 1.

Review Docker: Reviewed old projects and main commands for docker.

Create Sample Docker projects: Created a sample Docker Project, Did the getting started activities.

Repository for event project: The main repository for the event project.

Learn About RabbitMQ : Learned RabbitMQ components and Implemented them using Docker.

Review Scrum :  Reviewed the scrum guide and understand the process.

For the project, I am part of the reporting team. I mainly work on the event system software that sends and receives a message to other systems using the RabbitMQ messaging system interface. I also work with the database person and did make a docker example project and a cheat sheet of all the docker commands.

What worked well / did not work well

 The thing that worked well for our group is that we were good at organizing everything and everyone was responsible for certain tasks, and I noticed that some of the tasks overlap between us. For example, the backend person must work more closely with the database person. The first few days we were a little confused, but as everything came together our workflow improved tremendously, which helped to complete all the issues for sprint 1. One thing that did not work well is that we had few problems with GitLab, our template was not loading properly at the start so we could not assign proper labels to issues. Also, during meetings, we should have done the group tasks together instead of a person just doing the task.

What changes could be made to improve as a team?

For a project, communication is the key to success. I think that as a team we should be communicating more rather than doing our tasks during the meetings. For instance, if someone is struggling to figure something out, the other team members can help the person and give insights to lead the individual in the right direction. Also, for the next sprint when we are making cards we should be more specific about the descriptions and properly think about the issue and how we can achieve it and it is clear to the person what needs to be done.  

 What changes could be made to improve as an Individual.

As an Individual, the change that I can make is to plan properly for the next sprint. The first sprint I started of slow because I was not sure how you do something or if I am doing it the right way. A properly planned sprint will help me to go with a flow and have a balance rather than getting overwhelmed by doing all the tasks towards the end of the sprint. My communication with the team should get better as we move on to the next phase.

Overall, this was a great learning experience. I think the first sprint was a success and a starting point for our team to move forward with a vision to complete the task that is assigned for us. I’m looking forward to working with the other teams to combine everything and see our progress.

From the blog Derin's CS Journey by and used with permission of the author. All other rights reserved by the author.

Software Quality Assurance and Testing Blog Post #3 (Black-Box vs. Gray-Box vs. White/Clear-Box Testing)

On the first exam for my Software Quality Assurance and Testing course, and in activities previous to it, Black-Box, Gray-Box, and White/Clear-Box Testing were important topics/definitions to thoroughly understand. Not only did we have to know the meanings of these terms, but we had to be able to compare them and know how those testing methods are used. White/Clear-Box Testing is when the tester knows the contents of a function or method. This comes with its advantages and disadvantages of course. The advantages are that it is very easy to navigate the complexity, get legible test cases, and makes debugging smoother. The disadvantages would include bias being used by the tester and possibly longer and more expensive testing in general. On the other hand, Black Box testing is quite the opposite. The tester is not able to view the inner workings of the function/method and is only able to test based on what inputs are given and what outputs are received. Although this seems counterintuitive for a testing method, it also has advantages and disadvantages that make it a viable option. The advantages would be that it would take less time and expenses to test and that it eliminates tester bias altogether. The disadvantages are that because the tester is not able to see the inner workings of the function or method, it makes it harder to debug, find complexity, and have easy to read test cases. The two methods are basically opposites. Lastly, Gray-Box Testing is somewhere in-between the two. The tester knows a little bit about the inner workings of methods and functions, but is not focused on them completely like in White/Clear-Box Testing. This makes all of the advantages and disadvantages even out more overall which could be good in some cases but could also not be a valid testing option in other cases. Before this semester, I actually had never even heard of these terms, and it was interesting to go through and research them for this post and for my course!

From the blog CS@Worcester – Tim Drevitch CS Blog by timdrevitch and used with permission of the author. All other rights reserved by the author.

Apprenticeship Patterns Blog Post #7

For my second to last apprenticeship pattern blog post review, I would like to talk about simply because of how close it hits to home with me is the pattern entitled “Draw Your Own Map” in the textbook readings. This pattern is based on the fact that throughout the lives of software developers, there will be many times in which jobs or opportunities will not quite fit what they are capable of or are even interested in doing. The main issue brought up in this chapter was that none of the career paths provided to young software developers are often fitting for them. The reason that I chose to review this specific pattern is because I believe it relates to me very deeply as I am worried that whatever direction I end up taking after college may not be right for me. I already have many different options and directions that I could take from here and the opportunities are almost more daunting than exciting at this point. I am worried I will make the wrong choice early on. The book tried to solve this problem by basically saying that I choose my own destiny. “Identify a logical but ambitious next step for your career. Understand that it’s not up to your employer, your career counselor, or your professors to give you a hand up.” Sometimes the guidance of others is not what is needed even if it is with good intentions, because more often than not, I should know what I like best. The book also explains that no matter what direction I want to choose, it is important for me to make sure to take the first step. Without the first step, the dominos will not start falling and there will be no momentum toward my goals. If others (such as employers) try choosing a path that is not right for me, I must reflect and make the decision to stay on the course that I personally see best fitting for me. Obviously, when working, I should complete my roles and not give up, but in the end, it is not wrong for me to change direction and even switch career opportunities for my own betterment if I feel I need to.

From the blog CS@Worcester – Tim Drevitch CS Blog by timdrevitch and used with permission of the author. All other rights reserved by the author.

Sprint 1 Retrospective Blog

Links:

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/community/-/issues/2

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/community/-/issues/19

I worked on reviewing docker and creating a sample docker project with the links above. These were both team issues that we all worked on.

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/community/-/issues/10

I used tutorials online and several websites to review details about mongoDB.

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/community/-/issues/17

I created a sample mongoDB project for practice and getting familiarized with the database.

https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/reportingsystem/community/-/issues/9

This was for creating the main repository for the database that we will be using in reporting system.

The thing that worked well in this sprint for the group I was apart of, the reporting system, was that we organized each step of the way and tried to breakdown things to be more manageable. Each individual was responsible for certain tasks, such as in my scenario I was focusing on learning about the database aspect. Also, we had other issues assigned that were team based and so each individual in the group would work on that because it would be important for the whole team to learn about that specific issue. Overall, the planning at the beginning of the sprint helped keep the tasks we had to work on as a group clear, which led to us completing all the issues we assigned to ourselves.

Some things that didn’t work well was that we had problems in the beginning creating templates to explain what each issue was for on the cards. I think our group knew what we were supposed to do and communicated via discord, but didn’t put all the details we could have on the cards. Also, I think that when we have meetings we should focus on what we can do as a group that day and then on our own time work on the individual tasks.

Some changes we could have made as a team for future sprints are creating cards that aren’t so broad and keeping the issues more clear. Although it was the first sprint and there was a lot of learning to do, I believe that in the future when more implementations and detail will need to be done then it is important for us to break down the issues so they are representative of their point total. We can’t just put an issue and keep it so vague that once the sprint starts, it turns out the issue is a lot more complex than anticipated. Therefore, in the future as a group we can ask more questions for each issue assigned and say whether this will be enough of a task and whether the requirements are clear for the person to work on.

Changes I can make as an individual to improve the sprint is to start balancing out the work from the beginning of the sprint to the end. I feel like for the first sprint, I started off slow, in terms with how much work I got done, but towards the second half of the spring is where I completed most of the work. I think if I keep an equal balance and more momentum from the start, it will be a lot easier to manage and help myself as well as others to not be overwhelmed.

Overall, I think the first sprint was a success and it was really helpful working with a team on a project and deciding how we will break it down. I think when there is a full team working on creating something big, then each individual has ideas that we can use to help each other and be more creative in the process. The more ideas there are and brainstorming, the more thorough the end result will start to look. I am looking forward to the next sprint and further improve my experience with scrum in general.

From the blog CS@Worcester – Roller Coaster Coding Journey by fbaig34 and used with permission of the author. All other rights reserved by the author.

Improved Testing Methods

As a beginner programmer, testing my code meant putting in a few inputs, and if the code ran then I had myself a successful program. Recently, I’ve learned of two better testing methods that give you the information needed to ensure that the program can run given any particular scenario. These are Boundary Value Testing and Equivalence Class Testing. While they do work differently, both of these methods are similar in that they each choose an input based on the pool of values given the set conditions.

In Equivalence Class Testing, the focus is on the conditions. Looking at the given conditions, we can determine which values are valid and which are invalid. The range of valid values as well as the range for invalid values are the pool of values that will be tested, which are divided into intervals. For each interval, given an input, if it passes then it stands to reason that all inputs within the range of values will pass for that interval. By the same reasoning, if an input does not pass, all inputs within the range will not pass.

For example, consider a program that is testing for a vending machine, with a variable named cash for the amount of money the machine can accept. The range of valid values for cash is 0 <= cash <= 100. Now if we put in a value for cash that is between 0 and 100 and it passes, that means all values between 0 and 100 will pass. Likewise, if the value does not pass, then all values between the range will not pass. All values below 0 and above 100 are invalid, so testing those numbers will result in an error.

Boundary Value Testing is similar, in that we take valid and invalid values and test them. The difference is that there are 5 particular values we are testing. Say that the pool of values are between 0 and 100 inclusively. The values that will be tested are:
1. the minimum valid value, 0
2. the maximum valid value, 100
3. a nominal value between the minimum and maximum, 20
4. a value just below the minimum, -1
5. and a value just above the maximum, 101.

These inputs test all possible scenarios, therefore if they all pass, then the program is successful. The minimum, nominal, and maximum values test all valid inputs, and the minimum below and maximum above values test invalid inputs.

Equivalence testing and boundary testing are both great methods to use when testing your program. They can both be used to test valid and invalid values, and by doing so, are capable of ensuring that a program is error free.

Helpful Source:

https://www.guru99.com/equivalence-partitioning-boundary-value-analysis.html

From the blog CS@Worcester – CSBlogger by mjaber54 and used with permission of the author. All other rights reserved by the author.