Readers of the Software Testing Topics

Developers and Application Architects.

What will you learn from the topics?

Most of the time, we know the difference between Unit Testing and Integration Testing but when we start doing Unit testing, we mix Unit Test with an Integration Testing. Thus, I will explain the principles and best practice about Unit testing. We will know step by step how to write the test cases, using Behavior Driven Development (BDD) during White-box testing. The following concepts will be covered

Benefits of Software Testing

  • Reduce risk of failures when the systems are transferred to production or live operation.
  • Documental proof that business requirements have been met.
  • Assurance that the user is able to operate designed solution productively.
  • Assurance that the system works properly with the existing legacy systems.

Software Tester - Developer vs. Quality Assurance Engineer

Testing as a Developer

Developer can verify their implemented logics or codes according to the business requirement. Their main goal is to make sure that all the logics can run smoothly for position data. They also have to make sure that if end user passes any unexpected data, then the logics can still handle the exception for the negative or exceptional data and show the proper messages for it. This kind of testing is known as White-Box Testing because they can see their internal logics or codes. For example, an automated Unit-testing or an Automated Integration-testing.

Testing as a Quality Assurance (QA) Engineer

QA can verify the software according to business requirement but they don't need to worry about the logics or codes. They are just like an end user. They will input the positive data and they will expect the positive functionality from the output data. On the other hand, they will input the wrong data to make sure that they are getting the proper message for the wrong input. This kind of testing is known as a Black-Box Testing. Due to this, they can't see the internal logics or codes. They are verifying the external behavior from this test. For example, Acceptance testing.

Let's drilldown the basic testing concept

Test Document Basic

Test case & Test scenario

If you have to withdraw money from an ATM machine, then it is a scenario but to withdraw money, you need to execute many test cases.

Test-Case

A Test Case is a condition, which is executed for the expected output with the predefined set of steps with the known inputs.

Test scenarios

Test scenarios have multiple Test Cases. Thus, while starting testing, first prepare Test scenarios, followed by creating Test Cases for each scenario.

Example for Test Case & Test Scenario

Test Scenario-101

Checking the functionality of Login button.

Test Cases for this Test Scenario-101,

These all test-cases will have some expected, unexpected and an actual result.

Term of mistake

Positive Testing & Negative Testing

Positive Testing - - When the tester tests the Application with the valid input/data from positive point of view, then it is known as Positive testing.

Negative Testing - - When the tester tests the Application with an invalid input/data from negative point of view, then it is known as Negative testing.

White-Box & Black-Box Testing

Depending on the developers and QA Team, we can say that we have 2 types of testing. The developers can view the internal logics of the Implemented Application system or development box. This box is visible to the developer and it's called White-Box. On the other hand, QA team can't see the logical implementation and they can see the functionality of the system as an end user point of view. Due to this, the box is black and they test the external behaviors. It is called Black-Box testing.

Type of Tests depending on developer & QA Team

White Box Testing

Advantages of White Box testing

Disadvantages of White Box testing

Black Box testing

Advantages of Black Box testing

Disadvantages of Black Box testing

Black Box vs. White Box testing approach

Black-Box approach

White Box approach

Type of testing

Most common testing in many organizations

Granularity Levels

Unit testing

In this section, I will discuss in more detail about Unit testing. You will learn more about the testing principles and best practices. At the same time, I will show you complete practical examples step by step.

High level concept about Unit testing

This is White-box testing; where the developer checks their internal logics and functionality. Some developers don't like Unit testing. Another problem is sometimes they mix Unit testing with an Integration testing.

Top five excuses for not doing Unit testing

  1. I don’t have time to do Unit test.
  2. The office pays me to write down the codes, not to write down Unit test.
  3. I am supporting a legacy Application without Unit tests and existing design is not suitable for Unit test.
  4. QA and User Acceptance Testing are far more effective in finding the bugs.
  5. I don’t know how to write Unit test.

Advantages of Unit test

Disadvantages of Unit test

Best practices and principles to write Unit testing

Principles to write Unit testing

Principle 1. “Test the logic of the class only, nothing else

Note that this is one of the most important principles during Unit testing. When you are going to test a class, you should not have dependency on the database, file, registry, Web Services etc. You should be able to test any class in complete isolation and it should be designed to support complete isolation.

According to this principle, mock out all the external Services and state and remember Unit test never uses

Principle 2. “Fail first and set a guard on the door"

Before you write piece of logic, first write your fail test. Afterwards, add or refactor your guard logics and throw proper exceptions or messages for the negative or an exceptional data. Finally, run it and pass the test.

Explanation of Unit Testing principles

Principle 1 - Suppose, you have a method 'IsValidUser' to verify the user name and password for the login.

Now, if you look at the line number 15 and 17, then you will see class 'UserLogIn' has a dependency to the class 'UserDataAccess' and it is tightly coupled. Now, the problem is you need to test a method 'IsValidUser' of a class class 'UserLogIn' and you have to avoid the dependency. If you call 'sValidUser', then it will call the method GetUserInfoByUseeName(userName) and according to Unit test principle, if we have a dependency to a method of another class, then we have to mock that object class. It means that we have to inject some dummy data to that object. In this example, we need to inject dummy data for the 'GetUserInfoByUseeName(userName). If we do so, then we will be able to verify the logics of the method ('IsValidUser()') in the 'UserLogIn' class.

In order to avoid the tight coupling code, we need to refactor the code. Later, I will explain what are dependency, tight coupling and loose coupling. Now, my main goal is to make you know Unit testing principle only. Let's refactor the class again.

Now, the class 'RefactoringUserLogIn' is loosely coupled and you can inject the implemented class of the 'IUserDataAccess' ,which will make your life easy to do Unit testing. Note that there are many ways to inject the implemented class. Later, I will show you that as well as how to mock an object of a class. During Unit testing, if you mock the 'IUserDataAccess', it means that you are implementing a dummy object of 'IUserDataAccess' and the method 'IsValidUser()' , it will be not able to get any data directly from the database or ORM via 'UserDataAccess' class.

Principle 2

More than 50 percent people fail their road driving test first time, then after practicing on the highway and seeking tips from others, they are ensuring their success in the road test. If you are already familiar with the Test-Driven-Development (TDD), then you are already familiar with the fail test. I will explain TDD at the end of this section.

Let me explain the guard logics in the method and how it will help you to pass your Unit testing. Let's say that we have a method ‘GetSumByPositiveNumber()’ and it has two parameters. The business requirements are always to pass the positive numbers and get the sum. Never pass the negative or zero values for the methods.

Now, according to your business requirement, if you pass the values of the parameters like 1 and 2, then the method will return 3, which is correct but what happens, if you pass the negative values as a parameter or some combination like (-5, -1), (-5, 1), (5, 0), (0, 0) etc.

If we put some guard logics into the method, then the test should be passed. We are throwing the exception for the negative data.

Best practices for writing Unit Testing

Writing test scenario, test case and test data

Only Three Test Cases for Unit Testing, Nothing Else

  1. Positive Test Cases - Correct data to check for the correct output.
  2. Negative Test Cases - Broken or missing data to check for the proper handling.
  3. Exception Test Cases - Giving an unexpected data or behavior and check for the exception caught properly or not.

Test data according to the test cases

Let’s set some test data and consider “GetSum()” as an example. Here, my main goal is to show you how can we set some test data for the test cases.

Type of test data

  1. Positive Data
  2. Negative Data
  3. Exceptional Data

Positive data for positive test cases

The main goal of the positive test cases is to verify the functionality of the logics.

TestCase-1 - Given positive values should return the expected result

Negative Data for Negative Test Cases

The main goal of the negative test cases is to get proper messages for the bad input according to your business requirements.

TestCase-2 - Given invalid values, you should produce invalid argument message.

3.3.2.1.3 Exceptional data for exception test cases

The main goal of the exceptional test cases is to find out the proper exception handling with the proper messages, so that your code can’t break for the threshold limits.

Here, you can set the threshold limits of your test data. In .NET, the minimum value for a variable of type int is -2147483648 and the maximum value for a variable of type int is 2147483647.

TestCase3 - Given threshold limit values should throw an exception message.

Naming convention of Test Method for Unit testing

Traditional principle of Unit Test

One Test Method is written to test one and only one method and one assert method should test only one expectation at a time.

In a short the principle says – “one function/method and one assert per test method”

So, let’s consider the bellow example

Comparing the Traditional Principle to the Real World

Test Scenario

Verify the “GetSum” Method

Test Cases

Positive Test Cases

TC1 - Given positive values, should return expected result

Test Data-1 - firstValue =5, secondValue =6

Negative Test Cases

TC2 - Given zero values, should produce invalid argument message

Test Data-2 - firstValue =0, secondValue =0

TC3 - Given negative values, should produce invalid argument message

Test Data-3 - firstValue =-5, secondValue =-6

Exceptional Test Cases

TC4 - Given threshold limit values, should throw exception message

Test Data-4 - firstValue =2147483647, secondValue =2147483647

Test Method Example

Now according to the traditional principle, let’s write the test method for the “GetSum”

Now according to the traditional principle we have covered the Positive Test Case with “Test Data-1”. But what about negative and exceptional test cases??

How do we cover the negative and exceptional test cases with traditional principle??

Behavior Driven Development (BDD)

Why Do We Need BDD

If we want to cover all of the behaviors of our test cases according to our previous example then we need to follow some technique so that we can write down all of the behaviors of the method. So, The BDD is the technique which gives us the opportunity to fulfillment for all of the test cases with standard and readable naming convention. Many peoples, many minds. There are many techniques to write the naming convention of the test method. But if really depends on you and your preference. There is nothing right or wrong if you follow some other technique. Anyway, in a short we can say that In BDD, components test their expected behavior.

Concept of BDD

  1. Given I am a beginner to the BDD technique,I never used this technique before
  2. When I read this tutorial for BDD,
  3. then I have started liking it and I learn it.

BDD Naming convention

Test Scenario

Verify the “GetSum” Method

Test Cases

Positive Test Cases

TC1 - Given positive values, should return expected result

Test Data-1 - firstValue =5, secondValue =6

Test Method - Naming Convention,

GivenPositiveVaidValuesAsParams_WhenGetSumIsCalled_ThenItShouldReturnSumValue
Given_Positive_Vaid_Values_As_Params_When_GetSum_Is_Called_Then_It_Should_Return_Sum_Value

Negative Test Cases

TC2 - Given zero values, should produce invalid argument message

Test Data-2 - firstValue =0, secondValue =0

Test Method - Naming Convention,

GivenZeroValuesAsParams_WhenGetSumIsCalled_ThenItShouldThrowInvalidArgumentException
Given_Zero_Values_As_Params_When_GetSum_IsCalled_Then_It_Should_Throow_Invalid_Argument_Exception

TC3 - Given negative values, should produce invalid argument message

Test Data-3 - firstValue =-5, secondValue =-6

Test Method - Naming Convention,

GivenNegativeValues_WhenGetSumIsCalled_ThenItShouldThrowInvalidArgumentException
Given_Negative_Values_When_GetSum_Is_Called_Then_It_Should_Throw_Invalid_Argument_Exception

Exceptional Test Cases

TC4 - Given threshold limit values, should throw exception message

Test Data-4 - firstValue =2147483647, secondValue =2147483647

Test Method - Naming Convention

GivenMaxLimitValuesOfIntAsParams_WhenGetSumIsCalled_ThenItShouldThrowSumException
Given_Max_Limit_Values_Of_Int_As_Params_When_GetSum_IsCalled_Then_It_Should_Throw_Sum_Exception