-1

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();
}
Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101
  • Haven’t tried it myself, but using s3mock might be an option. See https://stackoverflow.com/questions/6615988/how-to-mock-amazon-s3-in-an-integration-test – Lesiak Jan 02 '22 at 18:46

1 Answers1

0

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.

Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101