Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 6, 2021 08:54 pm GMT

How To Unit Test Like a Pro

What Is Unit Testing

Testing a 'unit' in the system separately from other units.

But What Does a Unit Mean

There are a lot of different opinios regarding the answer to this question.

  • Some people say a unit is a function, some say it's a class.

However, the definition I find most logical is the one describing a unit as a 'behavior' of the system.

  • It's a scenario that has meaning in the business logic.

  • For example, create a new Shipment using the client's inputs, and save them to the database.

    • not really save, but fake it (mock it) we will see it a bit later

But Why Does The Behavior Description Seems The Most Logical

Tests would be closer to real-life

You wouldnt write useless tests. (for example, a useless null pointer check)

We can refactor our code without breaking tests since we test the outputs of a unit and not its inner workings

However, there are some things that we might not want to test in a unit

Like what?

Most commonly, dependencies on the outer world.

  • Database connection (get me the record with this Id)
  • API calls (call Twitter's API and get all my tweets)

Those dependencies we need to mock.
Mocking is defining how a dependency should act in certain conditions.

  • oh dear database connection, please return this object if your x method got called with the y parameter.

Let's look at an example

We have a Shipment class

@RequiredArgsConstructor  public class Shipment {     private final String productCode;     private final String owner;     private final int count;  }

Shipment Repository for database operations

public class ShipmentRepository {      public Optional<Shipment> findShipment(String owner, String productCode) {          // mock method    return Optional.empty();      }      public void save(Shipment shipment) {          // mock method    }  }

A validation service

public class VerificationService {      public boolean shipmentIsntValid(String owner, String productCode, int count) {          return owner.isEmpty()                  || productCode.isEmpty()                  || count < 0;      }  }

The Shipment service

@RequiredArgsConstructor  public class ShipmentService {      private final VerificationService verificationService;      private final ShipmentRepository shipmentRepository;      public String createAndSaveShipment(String owner, String productCode, int count){          if (verificationService.shipmentIsntValid(owner, productCode, count))              return "Shipment isn't valid";          if (shipmentExistInDB(owner, productCode))              return "Shipment Not Found";          createNewShipment(owner, productCode, count);          return "Shipment Is Created";      }      private void createNewShipment(String owner, String productCode, int count) {          Shipment shipment = new Shipment(owner, productCode, count);          shipmentRepository.save(shipment);      }      public boolean shipmentExistInDB(String owner, String productCode) {          return shipmentRepository.findShipment(owner, productCode).isPresent();      }  }

For the unit testing, we will use Junit5 and Mockito.

Let's look at a bad example of Unit Tests

@ExtendWith(MockitoExtension.class)  public class UniTestTests {      @Mock    ShipmentRepository shipmentRepo;      @Test    public void givenData_DetectValidity(){          VerificationService verificationService = new VerificationService();          boolean result = verificationService.shipmentIsntValid("jhon", "3HFF", 2);          assertFalse(result);      }      @Test    public void givenData_DetectShipmentExistsInDB(){          ShipmentService shipmentService = new ShipmentService(new VerificationService(), shipmentRepo);          Shipment shipment = new Shipment("ahmed", "3HKK", 4);          doReturn(Optional.of(shipment)).when(shipmentRepo).findShipment("ahmed", "3HKK");          boolean result = shipmentService.shipmentExistInDB("ahmed", "3HKK");          assertTrue(result);      }  }

Why are those bad unit tests?

  • ShipmentService and VerificationService are two closely related methods that work together to produce a single behavior (adding a new Shipment).
  • However, we are testing them in isolation, both in separate tests.

Now, Let's look at a good unit testing example

@ExtendWith(MockitoExtension.class)  public class UniTestTests {      @Mock    ShipmentRepository shipmentRepo;      @Test    public void givenShipmentData_CreateNewShipment(){          VerificationService verificationService = new VerificationService();          ShipmentService shipmentService = new ShipmentService(verificationService, shipmentRepo);          doReturn(Optional.empty()).when(shipmentRepo).findShipment("jalil", "3HXX");          doNothing().when(shipmentRepo).save(any());          String result = shipmentService.createAndSaveShipment("jalil", "3HXX", 10);          assertEquals("Shipment Is Created", result);      }  }

To Sum it in Few Words

A unit test is meant to validate how feature behavior in the system.
It could be a bunch of classes and functions interacting together to produce this behavior.

Source Code on GitHub


Original Link: https://dev.to/jarjanazy/how-to-unit-test-like-a-pro-59kj

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To