Category Archives: CS-443

Software QA Log #3: Introducing Boundary Value Testing

During my introductory programming classes, I tended to think that simply running my code and using random values as input to see if any errors popped up was more than enough to ensure that my code was (at least at the time) sound. Perhaps, in ideal circumstances this could be an ideal testing method. After all, if I had an inkling of an idea of what is considered a valid or invalid input, I could simply use some somewhat random input values, see what happens, and call it a day. It works, right?

As tempting as this may be, I am still working on understanding how functional software testing works, what techniques exist and can be used, and how to implement the tools that are created specifically for functional testing. In fact, I did talk about JUnit testing in a previous post, which can automate the process of testing for valid and invalid inputs that we provide to the software. If we were to just use random values without having a specific pattern in mind while testing software, what conclusions we would end up with by the end of testing would not mean much in the long run.

One efficient technique of testing for valid and invalid inputs is Boundary Value Testing or Boundary Value Analysis (two terms that I may be using interchangeably), a software testing technique for which test cases are being written based on what the programs define an acceptable range of inputs to be. To be more specific, when using boundary value testing, a tester may use the values at the boundaries of a range as inputs. In essence, we use the range or set of acceptable values for any variables in the code as the test cases, rather than simply coming up with random valid or invalid values at our own discretion. Moreover, to conduct boundary value testing we take values near and at the boundaries of a defined range [min, max], with some such values being:
1) max and min: the values at the extremes of a range
2) max-: the value just below the upper limit of a range
3) min+: the value just above the lower limit of a range
Boundary value analysis can include more values near the extremes of a range based on the needs of specific test cases, thus increasing the testing complexity, though the above mentioned are actually very common among all variations of boundary value testing, which may even include values that fall outside of the valid range. The above values fall within the acceptable (or valid) range of values, thus if they are provided as inputs during testing, we can expect to get reasonable outputs and behaviors from the software in return.

Here is an example of boundary value analysis using mathematical sets:
Suppose we have the variable x of type int that has acceptable values within the range [a,b]. This essentially means that we can define the valid range of x as {x: x ≥ a and x ≤ b}, meaning that any value within and including a and b will result in the program behaving in a reasonable manner. Any value that fits the invalid range of {x: x < a and x > b}, on the other hand, may result in the program throwing exceptions.

A simple example of boundary value testing being used in JAVA is the following:

Source: Boundary-value analysis (Wikipedia)

Though boundary value analysis may not absolutely prevent errors and bugs from occurring while testing software, it is an extremely good point of reference that a tester can use when they are testing code. If one expects the software to behave in certain ways depending on specific value intervals, it can be fairly easy for the tester to adjust their approach around such specific intervals and have a better understanding of the software they are testing and how it should work.

Articles/Websites I read that discuss the topic of this post in greater detail:
1) https://celestialsys.com/blog/software-testing-boundary-value-analysis-equivalence-partitioning/
2) https://www.eviltester.com/2019/01/what-is-boundary-value-analysis.html
3) https://qualitance.com/blog/boundary-value-analysis-and-equivalence-partitioning/
4) https://blog.qatestlab.com/2016/02/19/boundary-value-testing/

From the blog CS@Worcester – CompSci Log by sohoda and used with permission of the author. All other rights reserved by the author.

JUnit 5 and Gradle

In this second assignment for the software quality Assur & test we had to practice writing more Junit5 test cases. We had given three java classes, product, customer, and order. Our job was to write Junit5 test classes. Different from the week before this time we had more test cases to write. I liked and disliked this assignment because I enjoyed writing the test cases but the part that was not my favorite was running gradle in the project. It gave me a lot of trouble until I figure out what was wrong with it.

I believe that like me, many students or developers like to write Junit5 test cases. In our assignments we just scratch the surface of the features offered by JUnit 5. To find out more, go to the JUnit 5 documentation, it covers a huge host of topics, including the features we’ve have used until now and many more in detail. What I personally like about writing in Junit is that it follows a modular approach, which makes extending the API easier. It provides a separation of concern, where writing tests and discovering/running them is served from different APIs. In essence, three main modules exist within JUnit 5: JUnit Platform + JUnit Jupiter + JUnit Vintage.

Another obstacle that I had for this assignment was running gradle in program. Gradle is an open-source build automation tool that is designed to be flexible enough to build almost any type of software. What I like about it is that gradle avoids unnecessary work by only running the tasks that need to run because their inputs or outputs have changed. When I run gradle in my computer some of the test cases failed even though they passed in my environment. The main problem was in one test case. My solution to this problem is think another way you can write your test case, and that’s what I did. I changed the test cases and added some import statement that were missing and no issue after that.

Overall, I enjoyed this assignment. I like writing Junit5, but I don’t enjoy gradle. I had used it before and always causing trouble for me. Hope in the future that things will run smoothly.

From the blog CS@Worcester – Tech, Guaranteed by mshkurti and used with permission of the author. All other rights reserved by the author.

Software Quality Assurance and Testing Blog Post #2 (JUnit 5 Testing With Gradle)

The second assignment I worked on in my Software Quality Assurance and Testing class combined what we learned about JUnit 5 testing and using Gradle to automatically run all the tests fast and easy. This assignment proved to be more difficult than I was expecting, but in the end, I got very good at it and learned what I needed to. Downloading Gradle in the first place was my initial issue, since it seemed much easier to get it with a Windows machine than my Mac. Some classmates were kind enough to assist me and let me know about a software called Homebrew that basically is able to download Gradle for me. This was so helpful, and it was installed in no time! The second thing that make this assignment more difficult was that the actual tests I had to write were much harder than my first assignment. It took a lot of debugging and testing over and over again to finally get all of the tests to pass correctly. For some reason, many of the errors I ran into were primarily because I have made silly mistakes like grammar or syntax faults. All the repeated testing and debugging made me so much better at writing the methods correctly. The last thing that I would like to reflect on from this assignment is something I should have covered in my previous blog post. It is that pushing my projects to GitLab has changed. Of course, it has not changed that much, but just slightly. Rather than using the command “git push origin master,” I now have to write “git push origin main.” This is not too big of a deal for me, but at first I did not understand what I was doing wrong because of my pushes not working. I believe all of these things together will be a big part of my first exam in this class, and because of that, I am happy I was able to briefly discuss them in this blog to get a little extra review on them before that date!

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.

Software QA Log #2: I have been learning JUnit5 Testing lately.

In my previous blog-post, I talked about the importance of testing any product in order to ensure that it meets certain qualities and specifications, as well as work as intended. Software is among such products, as software goes through extensive testing before it becomes available to a wider range of users. Software testing includes conducting functional and non-functional testing, with the first focusing on testing if software runs as intended (by producing expect outputs and whatnot) and the latter focusing on non-functional aspects of software like performance. Today, I want to focus specifically on functional testing, more specifically on unit testing.

Although I wish to spend the rest of this post talking specifically about unit testing related to the JAVA programming language, I want to mention that unit testing is not exclusive to one programming language. During my earlier academic years, I learned to write unit test cases on C++ using CxxTest, an experience that I was able to carry over to JUnit5 as I started learning it in 2021.

Unit testing is a method of software testing that focuses on individual units of code. When testing for code written in object-oriented languages, a unit can be a function, a class, or an interface. While a novice programmer would simply run the code and provide their own input in order to determine whether the software behaves as expected, a programmer that is more familiar with using unit testing can automate the testing process by creating test cases for the units of code they wish to test, which would provide better coverage and much more insight to the tester regarding the behavior of the code compared to the feedback that simply running and inputting values to the code would provide. Though this method of testing is called “unit” testing, that is not to say that each function has to be tested in isolation. On the contrary, unit testing can be a very useful tool that can help a coder understand how each function interacts in tandem with other functions, which can make it much easier to troubleshoot and implement fixes.

As I mentioned earlier in this post, I began learning how to write JUnit5 unit test cases sometime earlier this year. Fundamentally, writing JUnit5 test cases is exactly the same thing as writing any other class in JAVA: it involves library imports, class definitions, instance variable and method implementations. Not too dissimilar to what a newer programmer would do when learning JAVA.

Depending on the kind and the complexity of test cases they could be writing, one could utilize the same functionalities that are used in the source code. The only difference is that JUnit5 introduces more functionalities that are used to run test cases. Such functionality is is the Assertions library. This method does the very thing a tester would do if they chose to run the code directly for testing; it checks if the value of output provided after execution is equal to the value a tester would expect the program to produce. Because it is possible to utilize multiple assertions in multiple test cases or for even multiple expected outputs, which can help save a tremendous amount of time of testing.

Though there are multiple other functionalities (such as annotations and whatnot), JUnit5 testing essentially boils down to its assertions; after all, it is the assertions that will show whether a test case has passed successfully and produced expected outputs, or has failed and has shown what has potentially gone awry.

The below image contains an example of a JUnit5 class with a test case:

Source: JUnit5 User Guide

One potential disadvantage that JUnit5 testing might present to programmers without much experience, such as myself, is that the order multiple test cases are run is not sequential. Rather, it is up to the compiler to run the test cases in any order it wishes to, which can be somewhat frustrating when the success or failure of a test case depends upon the success or failure of a test case(s) that exist(s) before it. Luckily, JUnit5 does have a way to run test cases in a specific order depending on the needs of the programmer who is writing the test cases.

Overall, learning how to write test cases can be a blessing for a programmer. Though this might not be necessary on programs of a smaller scale, it is extremely important to ensure that more complex software is tested thoroughly enough so that it functions at the best of its capabilities. After all, this blog is involved with Quality Assurance and Testing, thus making unit testing a very vital concept to be well-versed in.

Articles/Websites I read that discuss the topic of this post in greater detail:
1) https://www.edureka.co/blog/junit-tutorial/
2) https://junit.org/junit5/docs/current/user-guide/
3) https://www.h2kinfosys.com/blog/junit-testing/
4) https://blog.testproject.io/2019/02/26/junit-5/
5) https://smartbear.com/learn/automated-testing/software-testing-methodologies/

From the blog CS@Worcester – CompSci Log by sohoda and used with permission of the author. All other rights reserved by the author.

Behavior Driven Development

https://cucumber.io/docs/bdd/

            Since my last blog post for CS-443 focused on test driven development, I thought I was appropriate to talk about behavior driven development, also known as BDD for short, for this blog post. The reason I chose to write about this topic aside the reason just mentioned is because BDD is one of the topics covered in this class according to the syllabus. The article linked above acts as a tutorial for this type of development going through the specific procedure of BDD. According to the article, behavior driven development works as a three-step iterative process. The first step is to take a small upcoming change to the system, also known as a user story, and form concrete examples of new functionalities until they’re generally agreed upon. The second step documents those examples in a way that can be automated and checked for agreement. The final step implements the behavior described in the documents written in the previous step and begins with an automated test to guide the development of the code. This process continually adds a new behavior to the system each iterative loop.

            Before I wrote this blog post, I assumed that behavior driven development would have been a new concept to me unlike test driven development. However just like TDD, BDD is actually a concept I’m familiar with on some level. As I’ve taken computer science classes in WSU, I got into the habit of writing out what specific functions a program I’m working on needs. I wouldn’t go as far as create a user story for each task I’d have to do; that’s still a fairly new concept for me. But, just like the iterative nature of behavior driven development, I would document what behaviors a program needs to function and implement them into the code with some tests to guide development. Another thing that caught my attention is the last step of BDD which utilizes tests to give direction to the development of the code. Because of this, you could say that behavior driven development implements test driven development in its own way.  I don’t have much to add to this point, I just thought It was interesting enough to point out.

From the blog CS@Worcester – Rainiery&#039;s Blog by rainiery and used with permission of the author. All other rights reserved by the author.

Blog #2 Weak vs Normal (Equivalence Class Testing)

I wanted to look more into equivalence class testing after working with it on some of the class activities and having some trouble understanding some of its aspects, specifically the differences between weak and strong, and single fault assumption vs multi fault assumption.

Weak and Strong testing come in two forms each, Normal and Robust. Weak testing is meant to work with the single fault assumption, where one variable from each class is tested. With Weak Normal, only valid values are tested, while Weak Robust tests valid and invalid. Strong Normal testing works with the multi fault assumption, meaning that each valid possibility is tested, and Strong Robust testing works with each valid and invalid possibility.

Where I was getting confused and had to look more into equivalence class testing was the difference between working with one variable from each class and working with all possibilities, or more specifically, the single fault assumption and the multi fault assumption. When I was first looking at it and tried working on problems about this, they seemed the same to me because with each entry in the table I was making and other examples I looked at. It looked to me that both worked with multiple values of the variables that are in the range, so I got caught up on trying to see where I was making a mistake in my understanding.

Where I think I was making my mistake, and what I think the difference between the two is, is that with Weak test cases, one of the variables stays constant while the other goes through its different values. Then after several of those test cases, the latter variable stays constant at the nominal and the former changes values. Through this, one of the variables is getting testing at a time with the other values of the other variable, which is where the idea of testing one variable from each class comes from. I may be wrong about this, and this is just how I understood it.

So with Strong testing, this is where you can use any combination of valid values for the two variables for the test cases. This would increase the number of cases due to more possibilities. Then with Weak Robust and Strong Robust, you mostly do the same but include the invalid values with the valid ones from the Normal testing. In Weak Robust, one variable stays at the nominal while the other goes through a range of valid and invalid values, then do the same for the other variable. In Strong Robust, all valid and invalid possibilities for the variables are tested, leading to the highest amount of test cases out of the four techniques.

I think I have a better understanding of the differences between them after delving more into equivalence class testing and the different techniques associated with. My misunderstanding was how variables were being tested with the two assumptions because they seemed the same at first, but I can see how they are different now in their test cases and methods.

https://www.professionalqa.com/equivalence-class-testing

From the blog Jeffery Neal&#039;s Blog by jneal44 and used with permission of the author. All other rights reserved by the author.

Boundary Value Testing & Equivalence Partitions

            I was looking for some materials to supplement the work we are doing in Software Quality Assurance and Testing (CS-443) and I came across a nice article from ReQtest entitled What is Boundary Value Analysis and Equivalence Partitioning? I found this to be a good supplement to our in-class activity on boundary value testing, summarizing some of the key ideas. It helped me nail down the concepts and is a nice, short resource for me.

            The article begins describing boundary value analysis. It highlights it is focused on, well, the boundary values, as, “for the most part, errors are observed in the extreme ends of the input values.” This directly relates to the topics covered in class, but is limited as it is mostly focused on single inputs, rather than testing for multiple inputs like we did in class. The article then provides a couple example for an input domain of 1 to 100. The exact boundary values would be 1 and 100, just below boundary values would be 0 and 99, and just above boundary values would be 2 and 101. This seems similar to robust boundary value testing. However, the article doesn’t consider multiple inputs, so there is no noting of nominal inputs or the single fault assumption, or worst-case boundary value testing. Nonetheless, I find it is a concise way of summarizing normal boundary value testing.

            The article then goes on to describe equivalence partitioning, which is the division of, “test input data into a range of values and selecting one input value from each range.” This goes more towards describing the domain of input values and somewhat alludes to physical and arbitrary boundaries. These are not described within the article, but are worthy of noting. The example given is again in the 1 to 100 acceptable range. The article states that one valid input class is anywhere within the 1 to 100 range, another is any value below 1, and the last is any value above 100.

            Together, these two topics do well to sum up the different ranges of inputs for boundary value testing, with equivalence partitioning touching on a little bit of worst-case boundary value testing. Overall, I thought this was a worthwhile article and was helpful. I can see myself returning to it when I actually am writing tests. Boundary value testing is quite useful in many cases, so it’s a topic I’m happy and interesting in learning more about and practicing.  

From the blog CS@Worcester – Marcos Felipe&#039;s CS Blog by mfelipe98 and used with permission of the author. All other rights reserved by the author.

A quick but necessary recap on Boundary and Equivalence Class Testing

This week in class we covered what is Boundary Value Testing/Analysis and what is Equivalence Class Testing/Partitions and what are each of its subclasses.

After finishing the activities in class, I feel like the assignment really did a good job teaching us how to do each type of testing but it does not really explain why we should use each of these testing techniques.

While I think knowing how to conduct each of these testing techniques is important, the essentialist within me cannot stop thinking about the logic or the origin of these techniques. In this blog post, Mr. Eriksson gives a recap of the topics we covered in class and gives a couple short and easy to understand examples to work through. Also in this post, he gives a short explanation of the main ideas of each technique. The reason why I chose this specific blog post wasn’t because I wanted to introduce new information about the topic but because I wanted the topic a quick once-over and really nail down the topic. This blog post gives a really nice summary about what we covered in class and serves really nicely in filling the blanks in our understanding of the topic.

From the blog CS@Worcester – Just a Guy Passing By by Eric Nguyen and used with permission of the author. All other rights reserved by the author.

Static vs. Dynamic Testing

In this post I will be talking about what static and dynamic testing is and how they differ.

Static testing’s objective is to find and prevent any errors in the early stages of a software’s development. This sort of testing is done without execution of the code. Some methods of static testing are manual and/or automated reviews of the code, requirement documents and document design. Some examples of the documents reviewed in this stage are test cases, source code, user documents and web page content. This is primarily verification.

Dynamic testing’s objective is to check the functional behavior of software, how it conforms to the business requirements and fix any errors that have been found. Its system, its usage and its performance are tested through execution of code. This sort of testing is done at any stage of the testing life cycle and can be white or black box testing. Most of the time it is validating the outcome is what is expected.

Some key differences between the two types of testing are that in static testing you do not execute the program, you analyze and review the documents and code. In dynamic, you execute the program and analyze the behavior. The goal of static testing is to prevent defects when developing the software while the goal of dynamic testing is to fix the defects. The costs of finding defects in static testing is less than of dynamic testing and the return on investment for static is greater than of dynamic. This is because of the development stage that each are executed in. Since static testing is done in the early stage before compilation it is preventing before it happens. Since dynamic is performed at the end of the development stage, you are only fixing technical debt.

Techniques for static testing include technical reviews, inspection, code reviews, and walkthroughs. Techniques for dynamic include unit testing, integration testing and system testing. Ultimately, static testing involves some sort of checklist and process and dynamic testing includes test cases and execution.

Source: https://www.guru99.com/static-dynamic-testing.html#:~:text=Static%20testing%20is%20about%20the,testing%20is%20performed%20after%20compilation.

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.

differences and benefits between JUnit 4 to JUnit 5:

https://www.baeldung.com/junit-5-migration

According to this blog what I study for the Junit 4 and Junit5:

JUnit 5 is a powerful and flexible update to the JUnit framework, providing various improvements and new capabilities to organize and describe test cases and to help understand test results. Upgrade to JUnit 5 is quick and easy: Just update your project dependencies and start using the new functionality.

JUnit 4 bundles everything into a single JAR file.

JUnit 5 consists of three sub-projects, namely JUnit Platform, JUnit Jupiter, and JUnit Vintage.

1. JUnit platform

It defines TestEngine’s API for developing new testing frameworks that run on the platform.

2.JUnit Jupiter

It has all the new JUnit annotations and TestEngine implementations to run tests written with those annotations.

3.JUnit Vintage

Support for running tests written by JUnit 3 and JUnit 4 on the JUnit 5 platform.

But here are four strong reasons to start writing new test cases with JUnit 5:

JUnit 5 takes advantage of features from Java 8 or later, such as lambda functions, to make tests more powerful and easier to maintain.

JUnit 5 adds some very useful new capabilities for describing, organizing, and executing tests. For example, tests get better display names and can be organized hierarchically.

JUnit 5 is organized into multiple libraries, so import only the functionality you need into your project. With build systems like Maven and Gradle, it’s easy to include the right libraries.

JUnit 5 can use multiple extensions at the same time, something that JUnit 4 cannot do (you can only use one runner at a time). This means that you can easily combine Spring extensions with other extensions, such as your own custom extensions.

The JUnit 5 tests look pretty much the same as the JUnit 4 tests, but there are a few differences you should be aware of.

The import. JUnit 5 uses the new org.junit.jupiter package. . For example, org. Junit. Junit Test into org. Junit. Jupiter. API. Test.

Annotation. The @Test annotation no longer has arguments; each argument is moved to a function.

Assertions. JUnit Assertions 5 now in org. JUnit. Jupiter. API. Assertions. Most common assertions, such as assertEquals() and assertNotNull(), look the same as before, but with a few differences.

The hypothesis. Assumption has been moved to org. Junit. Jupiter. API. Assumptions.

In summary, JUnit 5’s tests are more powerful and easier to maintain. In addition, JUnit 5 offers many useful new features. Only the features you use will be imported, you can use multiple extensions, and you can even create your own custom extensions. Together with the new features, these changes provide a powerful and flexible update to the JUnit framework.

From the blog haorusong by and used with permission of the author. All other rights reserved by the author.