Author Archives: sohoda

Software QA Log #5: Learning and Utilizing Mockito

In a previous post I mentioned mocks in passing as one of the techniques used for test doubles. However, in that brief mention, I noted that mocks can be utilized in unit testing without having to create an actual object with actual values to test the behavior of a class. In essence, mocks aren’t too dissimilar to fakes or stubs; mocks are also pre-programmed to follow certain behaviors. However by utilizing mocks , unlike those test double techniques I mentioned in my previous post, programmers can utilize mocking testing frameworks, which can help significantly in automating and conducting unit testing. Though there are multiple mocking frameworks that can be utilized, I will be focusing mostly on Mockito as it is more well-known, however there are multiple other frameworks that may be stronger where Mockito is weak.

First, it is important to understand what a mock object is in order to understand how it can be used with frameworks like Mockito. Mock objects are essentially replicas of actual objects that are to be used in their place during behavior testing. By utilizing interfaces, a mock object can replicate the behavior of an original object without needing to address any other dependencies. Thus, mock testing allows us to test parts of a program without needing to use its resources themselves. One example where we would want to use mocks would be if our program needed to connect to a database and retrieve information. Instead of having to actually access the database and use real data, the mock object adjusts its behavior to accommodate for the specific unit test. In essence, mocks are similar to fakes.

An example of a mock is the following:

Source: https://dzone.com/articles/mockito-pros-cons-and-best

Unlike fakes, mocks can utilize multiple mocking frameworks. One such mocking framework is, as I mentioned earlier, Mockito. Mockito is a widely used JAVA-based mocking framework that can be often used in tandem with JUnit. Unlike JUnit, which is used to test the source code, Mockito uses mock objects to test in place of real objects. Moreover, unlike JUnit, Mockito can help in keeping track of when and how many times a method is being invoked and even verify if a certain method is being called, something that cannot be done right away with JUnit. However, along with the good things that Mockito brings to the table, Mockito has its own weaknesses, namely that it may not mock constructor methods as currently as version 3.x, or it cannot verify methods like toString().

Like with other test double techniques, mocking and Mockito are not the end-all be-all of testing, but some tools that can be utilized to help create and automate reliable tests for software. Depending on the software’s and the programmers’ needs, different frameworks or techniques might be preferable, however mocking and Mockito are among the solutions that one can learn and use.

Sources/Articles referenced:
1) https://www.toptal.com/java/a-guide-to-everyday-mockito
2) https://circleci.com/blog/how-to-test-software-part-i-mocking-stubbing-and-contract-testing/
3) https://www.accenture.com/us-en/blogs/software-engineering-blog/to-mock-or-not-to-mock-is-that-even-a-question
4) https://www.diffblue.com/blog/testing/mocking-best-practices/
5) https://swiftsenpai.com/testing/test-doubles-in-swift/
6) https://github.com/mockito/mockito/wiki/FAQ

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

Software QA Log #4: Utilizing Test Doubles

Although I may not have stated it explicitly, I wrote my previous post regarding using boundary values during testing on programs that are, more or less, complete with all the necessary functions having been implemented. That can be the case for a programmer who is working on software that is relatively small and can be coded to completion by a single individual. Though, one would ask, what happens when the project’s scale is large enough that multiple people would need to be assigned to code certain chunks of code that would be combined into a complete piece of software? The programmers may have some guidelines on or a semblance of how the software should work as a whole, including some of the parts they aren’t actually assigned to implement, yet they may not have the time or resources to work on the other functionalities on top of the ones assigned to them. Yet, to ensure that their assigned functionalities work according to specifications, they will still need the missing code to be implemented for which they may not know how to implement, mostly because of certain specifications that are expected to be met yet are unknown to the programmer. And the cycle continues.

In such cases, one technique that programmers can utilize in order to test their Work-In-Progress code without having to manually implement the missing code is test doubles. Essentially, programmers use test doubles as a way to make up for the missing functionalities by implementing simplified objects or methods such that the can still be run with minimal amount of code that can be easily replaced by the actual final product. Test doubles include, but are not limited to, the following:
1) Dummies
2) Stubs
3) Fakes
4) Mocks

I will be discussing Mocks along with Mockito in more detail in a later post. Instead, in this post I will be focusing on the first three types of test doubles that are given above. What I will mention about mocks, however, is that they can utilize the Mockito testing framework to automate and simplify the process of testing to a more significant degree compared to the previous three types. It goes without saying, however, that each approach has its own merits depending on the needs.

Dummies or dummy objects are objects or procedures with minimal, if any, implementation, making it by far the simplest form of test double implementation. In other words, dummy objects can be considered a bare-bone implementation of code that is sufficient enough to help in testing. Below is a simple example of a dummy object:

public DummyObject(){
}
Essentially, the above dummy object is more than enough code even though lacks the implementation. Dummy objects are created to be used when other methods may require parameters, though in this particular case we are not actually creating the objects ourselves.

Stubs are (or I at least believe they are) a more common method of testing methods. Essentially, stubs contain slightly more (yet still bare-bones) implementation than dummies, which is more often than not a predefined return value that corresponds to the return type. Below is an example of a stub method:
public double average(double a, double b){
return 3.1;
}
In the above example, the method will not do any calculations. Instead, it will return an arbitrary value that is relevant to the return type, without any other significance whatsoever. Stubs are used to test if the method actually responds when being called during testing, rather than if the method produces an expected result after running a specific set of computations. I have found myself using stubs when programming in C earlier in my studies just to make sure if other parts of my code can be compiled properly, though now I know that stubs may also be used in unit testing as well.

The last type of test doubles I will be talking about is fakes. Fakes or fake objects have some implementation, though this implementation is often different from that in the end product. Fake objects do not actually use resources (such as data from a database) but may use some arbitrary data in order for the object to be used in testing. An example of a fake object is given below:

Source: https://www.softwaretestingmagazine.com/knowledge/unit-testing-fakes-mocks-and-stubs/

Compared to stubs and dummies, fakes contain more implementation, though they are much “lighter” to use than actual objects that contain data that may need to be retrieved in one way or another.

Overall, which of the above implementations may need to be used in testing depends solely on the programmer’s judgement and the state of their code. When combined with other testing techniques (such as boundary value testing), unit testing may provide enough insight to the developers in order to make the appropriate adjustments to their software, be it in regards to fixing faulty code or implementing better optimization. Like I mentioned earlier, each technique has its own merits depending on the circumstances. Moreover, in my next post I will be discussing Mock objects, the Mockito testing framework, and some of the advantages Mockito brings to software testing.

SOURCES:
1) https://swiftsenpai.com/testing/test-doubles-in-swift/
2) https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da
3) https://www.martinfowler.com/bliki/TestDouble.html
4) https://docs.microsoft.com/en-us/ef/ef6/fundamentals/testing/writing-test-doubles
5) https://dzone.com/articles/test-doubles-mockito
6) https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da?gi=5be6b5dbca4d

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

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.

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.

Software QA Log #1: Understanding Quality Assurance

Even though we don’t consciously think about this fact, many products that we use in our daily lives are made with particular specifications and go through rigorous testing and quality assurance before they are put out for public use. Regardless of the complexity, every product that we use is expected to go through particular standardized procedures that will ensure that the product can fulfill certain specifications before it is put out for any kind of use. Essentially, everything created that is meant for use goes through the process of Quality Assurance (QA) and Quality Control (QC) in order to ensure that quality specifications are met and that the end result of a product is satisfactory.

Components of computer systems, specifically software (as it is the focus of this blog), are among those products that go through the process of QA and QC testing before they are released to the end consumers in order to ensure that quality specifications are met and that the products released are the best that they can possibly be in regards to performance, security, and whatnot. Essentially, QA and QC testing in regards to software are what separate a good product of code from a defective code of lesser quality. Though both QA and QC testing are important parts of software development, it is important to properly define each terms and to make a distinction between the two. Though I will be using this blog to discuss Software Quality Assurance Testing specifically, I believe it would be helpful to understand the distinctions between Quality Assurance and Quality Control.

In software engineering, quality assurance is a set of standardized procedures whose aim is to ensure that certain specifications of quality are being met during development, therefore making this process a core part of software development. On the contrary, quality control is a process of software engineering which evaluates the quality of the end product, meaning that this process occurs after development and before a product is distributed rather than alongside it. While both processes make sure that quality standards of software are met, their difference lies on which part of development they typically occur in. Moreover, in the context of software development, QA ensures that certain defects, such as bugs, are properly taken care of during development, whereas QC might address less technical issues that could still impact the quality of the end product if left unaddressed and ensure that improvements to the end product are made accordingly.

There are multiple methods of QA Testing which may be divided into two types, functional and non-functional. Functional QA testing ensures that the software works as intended depending on the inputs or overall interactions an end user has with it. On the other hand, non-functional QA testing aims to conduct tests regarding (but not limited to):

  1. Vulnerability/Security: such testing ensures that there are no security risks that would result in the system the software was installed on to be compromised by any means (i.e. hacking, data leaks)
  2. Compatibility: such test ensures that the software is fully compatible with and can be implemented on the system it was created to run on.
  3. Usability: such test ensures that the software is intuitive and can be used by end users with minimal difficulty (i.e. user-friendly GUI)
  4. Performance: such test ensures that the software can work in a variety of situations on the system it is implemented on, along with making sure that it can operate within the system’s limitations

In order to make sure that software performs well on a functional level, it often goes through rigorous unit and integration testing, both of which are used to ensure that software can perform by examining how parts of code (i.e. functions) work both independently and in union. Though these kinds of functional testing may often be slow and repetitive, they can often help uncover bugs and glitches that may occur when software executes and can help resolving any defects much easier.

Quality assurance is (or should be for some) an integral part of software development. It is not simply enough to write code that can be compiled and executed without error. It is important, however, to ensure that the software that is being developed meets certain quality standards both on a functional and a non-functional aspect in order to create a competent piece of software.

Articles I read that discuss this post’s topic in greater depth:
1) https://www.tiempodev.com/blog/what-is-qa-in-software-testing/
2)https://mycrowd.com/blog/what-qa-testing-methodologies-are-there/
3)https://www.thebalancesmb.com/definition-of-quality-assurance-2533665

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

CS-443 Introduction

To the reader who is currently viewing my blog, hello!

My name is Sofia Hoda. As of the writing on this post, I am on my second year at Worcester State University and am currently a Computer Science major with a focus on Software Development. During my studies I work as a Mathematics tutor at a community college, which brings me much joy. If time permits in the future, I hope to study further so I can incorporate Mathematics and Software Development in my future career.

I created this blog to catalogue my findings regarding Computer Science while I am taking my CS-443 course, though I hope I get to use it as a way to also talk about any future projects I might work on.

I will do my best to make this blog interesting for anyone who may come across it. And to the readers who are also taking CS-443 on SP21, I hope we get along this semester and do our best!

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