'Increase code coverage on method local objects or 3rd party library objects creation or 3rd party functions call

I have to unit test the below method, whereas all the lines of this code related to third party aws library. The method also returns nothing. So only test I can do is verifying the exception. Any other test can I do to improve the code coverage?

public void multipartUpload() throws InterruptedException {

    TransferManager tm = TransferManagerBuilder.standard()
                                               .withS3Client(s3Client)
                                               .withMultipartUploadThreshold(1024l)
                                               .build();

    PutObjectRequest request = new PutObjectRequest(bucketName, keyName, filePath);
    Upload upload = tm.upload(request);
    upload.waitForCompletion();
}


Solution 1:[1]

Let see the code that needs to be tested:

public class DemoCodeCoverage {

    public void showDemo(LibraryCode library) {

        System.out.println("Hello World!");
        library.runDemoApplication();
        // Extract the below code to a method since LibraryCode is not passed
        // Then ignore running that method
        //        LibraryCode library = new LibraryCode()
        //        library.runDemoApplication_1();
        //        library.runDemoApplication_2();
        //        library.runDemoApplication_3();
        System.out.println("World ends here!");
    }

    public boolean showBranchingDemo(boolean signal) {

        if (signal) {

            signalShown();
        } else {

            noSignal();
        }

        return signal;
    }

    public void signalShown() {

        System.out.println("signalShown!");
    }

    public void noSignal() {

        System.out.println("NoSignal!");
    }
}


public class LibraryCode {

    // Library can be AWS/Database code which needs authentication
    // And this authentication is not a concern for our UT
    // Still will end up execption when we do our UT
    public void runDemoApplication() {
        throw new RuntimeException();
    }
}

Below can give good code coverage:

public class DemoCodeCoverageTest {

    @Test
    public void testShowDemo() {

       DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
       LibraryCode lib = Mockito.mock(LibraryCode.class);
       Mockito.doNothing().when(lib).runDemoApplication();
       t.showDemo(lib);
//        when(bloMock.doSomeStuff()).thenReturn(1);
//        doReturn(1).when(bloMock).doSomeStuff();
    }

    @Test
    public void testShowBranchingDemo() {

        DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
        assertEquals(true, t.showBranchingDemo(true));
        assertEquals(false, t.showBranchingDemo(false));
    }

    @Test
    public void testSignalShown() {

        DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
        t.showBranchingDemo(true);
        Mockito.verify(t, times(1)).signalShown();
    }

    @Test
    public void testNoSignal() {

        DemoCodeCoverage t = Mockito.spy(new DemoCodeCoverage());
        t.showBranchingDemo(false);
        Mockito.verify(t, times(1)).noSignal();
    }
}

Below are the steps to increase the test code coverage:

Case_1: Testing void method

Assume you have method the does not take any params and return nothing.

public void printHelloWorld() {

    System.out.println("Hello World")
}

Still you can write test that calls this method and returns successfully without any runtimeException. Actually we haven't tested anything here other than giving a option to run the code by our tests. Thus increase the code coverage. Additionally you can verify the invocation:

    Mockito.verify(instance, times(1)).printHelloWorld();

There are circumstances you cannot test those, example say it is third party library call, then the library might have tested already, we just need to run through it.

@Test
public void testPrintHelloWorld() {

    // may be hibernate call/other 3rd party method call
    instance.printHelloWorld();
}

If your tool is not strict for 100% code coverage, you can even ignore it and justify it.

Case_2: Testing a method with object created and called another method inside the testing method

Assume you have method the does call DB to add entry in Hello_World table also prints it in console like below.

public void printHelloWorld() throws DBException {

    DBConnection db = new DBConnection();
    db.createEntry(TABLE_NAME, "Hello World");
    System.out.println("Hello World")
}

You can extract those db code into new method, then test it separately.

public void printHelloWorld() throws DBException {

    makeHelloWorldEntryInTable();
    System.out.println("Hello World")
}   

public void makeHelloWorldEntryInTable() throws DBException {

    DBConnection db = new DBConnection();
    db.createEntry(TABLE_NAME, "Hello World");
}

While testing with DB you would expect the DBConnectionException as it is just unit test. So one test with @Test(expected=DBException) for makeHelloWorldEntryInTable, and another test on printHelloWorld() with skipping the method makeHelloWorldEntryInTable call like below. Thus increases the code coverage.

@Test(expected=DBException)
public void testMakeHelloWorldEntryInTable() {

    //This can any third party library which cannot be configured for ut.
    //One example is testing the AWS bucket exist or not.
    instance.makeHelloWorldEntryInTable();
}

@Test
public void testPrintHelloWorld() {

  Mockito.doNothing()
         .when(localInstance)
         .makeHelloWorldEntryInTable();

  localInstance.printHelloWorld();
}

Case_3: if you have private method, then make it default package level and test it. Thus improves the code coverage.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1