DEV Community

Cover image for JUnit and Mockito: Introduction Unit Test
Israel-Lopes
Israel-Lopes

Posted on • Updated on

JUnit and Mockito: Introduction Unit Test

AssertTrue

AssertTrue, takes a boolean as a parameter. This is the simplest of all.

It checks if the expression is true.

Assert.assertTrue(true);
Enter fullscreen mode Exit fullscreen mode

OBS: Recommends If you use a minimum of negative expressions.

AssertFalse

AssertFalse validates whether the expression is false.

assertFalse(false);
Enter fullscreen mode Exit fullscreen mode

AssertEquals

Its operation is very simple, it validates if the expected value is equal to the current one.

assertEquals(expectedValue, current);
Enter fullscreen mode Exit fullscreen mode

To use Equals to compare decimal places, use the comparison delta.

The delta would be a margin of error for comparison.

assertEquals(expectedValue, current, delta);
Enter fullscreen mode Exit fullscreen mode

Example:

assertEquals(0.51, 0.51, 0.01);
Enter fullscreen mode Exit fullscreen mode

AssertThat

Basically AssethThat means, verify that.

In assertThat and the inverse of assertEqual, the first value and the current, the second and the match.

Here is checking if the expected value is equal to 5.0

asserthThat(allocation.getValue(), CoreMatchers.is(5.0));
Enter fullscreen mode Exit fullscreen mode

another way to do

assethThat(allocation.getValue(), is(equalsTo(5.0)));
Enter fullscreen mode Exit fullscreen mode

Denial: Check that negation value, not and 6.

assethThat(allocation.getValue(), is(not(6.0)));
Enter fullscreen mode Exit fullscreen mode

With Date: Checks if the date is true.

assethThat(allocation.getValue(), new Date(), is(true));
Enter fullscreen mode Exit fullscreen mode

OBS: Ideally, for each test there is an assertion.

Rule

With rule you can do several tests and just one, thus losing the need to split tests.

Example:

@Rule
public ErrorCollector erro = new ErrorCollector();
erro.checkThat(allocation.getValue(), is(equalsTo(6.0)));
erro.checkThat(isMesmaData(allocation.getDateAllocation(), new Date()), is(true));
Enter fullscreen mode Exit fullscreen mode

In this example above, unlike an AssethThat, it will check one by one, even if it fails.

Making sure you don't fail

@Rule
public ErroCollector error = new ErroCollector();
@Test
public void testAllocation() {
    // Scenery 
    AllocationService service = new AllocationService();
    User user = new User("User !");
    Movie movie = new Movie("Movie 1", 2, 5.0);
    // Action
    try {
        service.rentMovie(user, movie);
        Assert.fail("Should have thrown an exception");
    } cathc (Exception e) {
        assertThat(e.getMessage(), is("Film out of stock"));
    }
}
Enter fullscreen mode Exit fullscreen mode

To ensure that a test passes and does not fail, you can create a try catch with Assert.fail.

The safest way to work with exceptions is with try catch.

Another way of working with exceptions.

@Rule
public ExpectedException execption = ExpectedException.none();
@Test
public void testAllocation() {
    // Scenery 
    AllocationService service = new AllocationService();
    User user = new User("User !");
    Movie movie = new Movie("Movie 1", 2, 5.0);
    // Action
    service.rentMovie(user, movie);
    exception.expect(Excption.class);
    exception.expectMessage("Film out of stock");
}
Enter fullscreen mode Exit fullscreen mode

Another way is also with expected. In the method header, inside the @test annotation. So it will catch the exception described inside.

@Test(expected = FilmOutOfStockException.class)
public void testAllocation() throws Exception {
Enter fullscreen mode Exit fullscreen mode

Another way to test and verify posted messages.

if (movie == null) {
    throw new LessorException("Empty user");
}
Enter fullscreen mode Exit fullscreen mode

Here will capture the message when exception was thrown:

exception.expect(LessorException.class);
exception.expectMessage("Empty user");
Enter fullscreen mode Exit fullscreen mode

Before and After

There are two annotations that allow code blocks to be executed before and after each test.

First one and @Before. With it it is possible that it is executed first, before the test. Follow the example below.

@Before
public void setup() {
    System.out.println("before");
}
Enter fullscreen mode Exit fullscreen mode

Another is @After, it runs after each test.

@After
public void setup() {
    System.out.println("after");
}
Enter fullscreen mode Exit fullscreen mode

The @Before and @After are executed one by one for each test, over and over again.

An example of using @Before would be to initialize common classes between tests.

Example:

private AllocationService service;
@Before
public void setup() {
    service = new AllocationService();
}
Enter fullscreen mode Exit fullscreen mode

Another way also to initialize is with BeforeClass and AfterClass, which is initialized after and before the class is initialized or terminated. Their implementation is similar to Before, however the method containing this annotation must be static*.

@BeforeClass
public static void setup() {
    System.out.println("before class");
}
Enter fullscreen mode Exit fullscreen mode

OBS: Static variables in class scope JUnit does not reset.

Running tests in order

To run the tests in order, you must create the methods without the @test annotation. This creates a general test to run. Below is an example.

public static counter = 0;
public void start() {
    counter = 1;
}
public void check() {
    Assert.assertEqual(1, counter);
}
@Test
public void testAll() {
    start();
    check();
}
Enter fullscreen mode Exit fullscreen mode

This way it is guaranteed that the start() method will be executed first and then check().

There is another way to do this, which is the most suitable way and with @FixMethodOrder() annotation, which is used in the class header.

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrderTest() {
public static counter = 0;
@Test
public void t1_start() {
    counter = 1;
}
@Test
public void t2_check() {
    Assert.assertEqual(1, counter);
}
Enter fullscreen mode Exit fullscreen mode

In this example the test methods were executed in alphabetical order, however there are other ways to define this execution route.

@Ignore and Assumptions

With @Ignore, we can ignore unwanted tests.

@Test
@Ignorer
public void shouldTest() {
    }
Enter fullscreen mode Exit fullscreen mode

Another way is using Assumptions, an example of its use and defining that the test would only be executed on a Saturday.

@Test
public void shouldTest() {
    Assume.assumeTrue(DataUtils.checkDayOfWeek(new Date(), Calendar.SATURDAY));
    }
Enter fullscreen mode Exit fullscreen mode

Parameterized tests

Junit provides a way to parameterize tests, which is called parametrizer, with it it is possible to reduce the number of repeated lines of code in tests.

To initialize it, we must put it at the top of the class, being it @RunWith(Parameterized.class). That way JUnit already knows that the test of this class will be parameterized.

Next step now is to define the dataset that will be tested. In the getParametros method, which will be the data source, we must inform this to JUnit. For this we must use the annotation @Parameters, don't forget that and in the plural.

OBS: The parameters method must always be static.

Next step now is to define the link of the variables that are used in the getParameters method, they are filmes and AllocationValue.

OBS: These variables must be public, otherwise it will give access error.

@RunWith(Parameterized.class)
public class CalcValueAllocationTest {
    private AllocationService service;
    @Parameter
    public List<Movie> movies;
    @Parameter(value=1)
    public Double valueAllocation;
    @Before
    public void setup() {
        service = new AllocationService();
    }
    private static Movie movie1 = new Movie("Movie 1", 2, 4.0);
    private static Movie movie2 = new Movie("Movie 2", 2, 4.0);
    private static Movie movie3 = new Movie("Movie 3", 2, 4.0);
    private static Movie movie4 = new Movie("Movie 4", 2, 4.0);
    private static Movie movie5 = new Movie("Movie 5", 2, 4.0);
    private static Movie movie6 = new Movie("Movie 6", 2, 4.0);
    @Parameters
    public static Collection<Object[]> getParameters() {
        return Arrays.asList(new Object[][] {
            {Arrays.asList(movie1, movie2, movie3), 11.0},
            {Arrays.asList(movie1, movie2, movie3, movie4), 13.0},
            {Arrays.asList(movie1, movie2, movie3, movie4, movie5), 14.0},
            {Arrays.asList(movie1, movie2, movie3, movie4, movie5, movie6), 14.0}
        });
    }
    @Test
    public void mustCalculateLeaseValueConsideringDiscounts() throws OutofStockFilmException, RentalCompanyException {
        // Scenery
        User user = new User("User 1");
        // Action
        Allocation result = service.alugarFilme(user, movie);
        // Check
        assertThat(result.getValue(), is(valueRentalCompany));
    }
}
Enter fullscreen mode Exit fullscreen mode

Test Suite

First of all, to use the suite, you must create a class for it, because it is where the other tests will be called.

In @RunWith(Suite.class) we tell JUnit that our test will be initialized as a suite.

In the annotation @SuiteClass({}), it is defined all the tests that will be executed by this suite. Inside it will be placed all the classes that must be tested.

@RunWith(Suite.class)
@SuiteClass({
    CalculatorTest.class,
    CalcValueRentalCompany.class,
    RentalCompanyServiceTest.class
})
public class SuiteExecution {
}
Enter fullscreen mode Exit fullscreen mode

InjectMocks

With the @InjectMocks annotation, it creates an instance of the class and injects the mocks that are created with the @Mock annotation or in this instance @spy. And for that, you must also use @RunWith(MockitoJunitRunner.class) or Mockito.initMocks(this) to initialize these mocks and inject them.

Spy

The annotation @spy is similar to @Mock but in reverse.
Mock it returns the default value, while Spy returns the method execution.

OBS: @spy does not work with interface, only with concrete classes.``

Texto alternativo da imagem)

Top comments (0)