Static vs. Dynamic Testing

Software testing falls largely into two categories: static and dynamic. Both are valuable, but the scenario around the test being performed determines which method best fits.

Static testing is a testing technique that does not require the code to execute. This can include manual or automated reviews of the code, requirement documents, and document design, all of which are intended to catch errors in the code. Static testing is done in order to prevent errors during the early stages of development and can help locate errors undetected through dynamic testing methods. Reviews are an important facet of static testing and are the primary method for carrying out a static test. A review is a meeting or other process aimed at locating flaws and defects in the design of a program. Apart from physical walkthroughs of the code, there exist tools that automatically search for errors. These tools, such as CheckStyle and SourceMeter, can help developers adhere to standards in code and style.

Dynamic testing is a testing technique that checks the program’s behavior when code is executed. As the name suggests, it is intended to test the dynamic behavior of a software. This encompasses a vast majority of the testing methods we’ve discussed both in this class and on this blog. The two types of dynamic testing are white and black box testing, which are both techniques that I have discussed on this blog before. Dynamic testing ensures that a software is working properly during and after its installation, it makes sure that the software is stable, and it encourages consistency in the software’s functionality.


Test Doubles

Test doubles are a method of unit testing that allows a user to test how the code interacts with an external dependency. It is intended to focus on the code being tested rather than the behavior of the external dependencies. As such, a preset object is used to represent those dependencies and their intended behavior. This allows a section of code to be tested even when its external dependencies are not yet finished or are not yet working. There are several types of objects used as test doubles: dummies, fakes, stubs, and mocks.

Dummies are objects that are passed but never used. In most instances, they are only used to fill out a parameter and are used as a placeholder for arguments.

Fakes are objects that simulate the external dependency by implementing the same interface without interacting with any other objects. Fakes are typically hard-coded in order to represent the correct behavior and must be modified whenever the interface is modified. A new fake object must be created for every unique test case.

Stubs are objects which return a result based on specific input, and they do not usually react beyond the scope of the test. Stubs will usually have all the methods required by the external dependency but will provide hard-coded returns that may need to be altered depending on the test case.

Mocks, much like stubs, will return a result based on a specific input. Mocks can also be programmed with data like the number of times its methods should be called and in what order.


Boundary Value and Equivalence Class Testing

When testing a software, it is important to consider what inputs will be used and how they will affect the outcome and usefulness of the test. There are several design techniques for determining input variables for test cases, but the two I will focus on in this post are boundary value and equivalence class.

Boundary value testing is designed to, as the name suggests, test the boundary values of a given variable. Specifically, this test design technique is intended to test the extreme minimum, center, and extreme maximum values of a variable, and it assumes that a single variable is faulty. In normal boundary value testing, the following values are selected for a given variable: the minimum possible value, the minimum possible value plus one, the median value, the maximum possible value minus one, and the maximum possible value. Normal testing only tests valid inputs. Robust boundary value testing, in addition to testing the values of normal testing, tests invalid values. This includes the minimum value minus one and the maximum value plus one.

Equivalence class testing divides the possible values of a variable into equivalence classes dependent on the output that value represents. Equivalence class testing can also be divided into robust and normal where robust testing includes invalid values and normal does not. In addition, equivalence class testing can also be weak or strong. Weak testing only tests one value from each partition and assumes that a single variable is at fault. Strong testing tests all possible combinations of equivalence classes and assumes that multiple variables are at fault.



Something that has haunted me since last semester is Gradle. Gradle is a flexible tool used in the automation process that can build nearly any software and allows for the testing of that software to happen automatically. I know how to use it, but it has been difficult for me to understand how Gradle actually works. So I wanted to do some research and attempt to rectify this.

Gradle’s own user manual, linked below in the ‘Sources’ section, provides a high-level summary of the tool’s inner workings that has been instrumental in developing my own understanding of it. According to the manual, Gradle “models its builds as Directed Acyclic Graphs (DAGs) of tasks (units of work).” When building a project, Gradle will set up a series of tasks to be linked together. This linkage, which considers the dependencies of each task, forms the DAG. This modeling is accessible to most build processes, which allows Gradle to be so flexible. The actual tasks consist of actions, inputs, and outputs.

Gradle’s build lifecycle is comprised of three phases: initialization, configuration, and execution. During the initialization phase, Gradle establishes the environment the build will utilize and determines which projects are involved in the build. The configuration phase builds the Directed Acyclic Graph discussed previously. It evaluates the project’s code, configures the tasks that need to be executed, and it determines the order in which those tasks must be executed. This evaluation happens every time the build is run. Those tasks are then executed during the execution phase.


White Box Testing vs. Black Box Testing

When considering how to test a software, there are two major options: white box testing and black box testing. Both are uniquely useful depending on the purpose of your test.

White box testing is a technique that examines the code and internal structure of a software. This technique is often automated and used within CI / CD pipelines. It is intended to focus on the implementation and architecture of an application’s code. As such, this testing technique is useful in identifying security risks, finding flaws in the code’s logic, and testing the implementation of the code’s algorithms. Some examples of white box testing include unit testing, integration testing, and static code analysis.

Black box testing is a technique that tests a system and requires no knowledge of that system’s code. This technique involves a tester providing input to the system and monitoring for an expected output. It is meant to focus on user interaction with the system and can be used to identify issues with usability, reliability, and system responses to unexpected input. Unlike white box testing, black box testing is difficult to fully automate. In the event of a failed test, it can be difficult to determine the source of the failure. Some examples of black box testing include functional testing, non-functional testing, and regression testing.

Grey box testing exists in addition to these. It is a combination of white and black box testing which tests a system from the perspective of the user but also requires a limited understanding of the system’s inner structure. This allows the application to be tested for both internal and external security threats. Some examples of grey box testing include matrix testing, regression testing, and pattern testing.