【问题标题】:Increase code coverage on method local objects or 3rd party library objects creation or 3rd party functions call增加方法本地对象或第 3 方库对象创建或第 3 方函数调用的代码覆盖率
【发布时间】:2022-01-02 14:29:09
【问题描述】:

我必须对以下方法进行单元测试,而此代码的所有行都与第三方 aws 库相关。该方法也没有返回任何内容。所以我能做的唯一测试就是验证异常。我可以做任何其他测试来提高代码覆盖率吗?

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();
}

【问题讨论】:

标签: java unit-testing mockito code-coverage


【解决方案1】:

让我们看看需要测试的代码:

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();
    }
}

下面可以给出很好的代码覆盖率:

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();
    }
}

以下是增加测试代码覆盖率的步骤:

案例_1:测试void方法

假设您有一个不带任何参数且不返回任何内容的方法。

public void printHelloWorld() {

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

您仍然可以编写调用此方法并成功返回而没有任何 runtimeException 的测试。 实际上,除了提供通过我们的测试运行代码的选项之外,我们还没有在这里测试任何东西。从而增加代码覆盖率。 此外,您可以验证调用:

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

有些情况你不能测试,比如第三方库调用,那么库可能已经测试过了,我们只需要跑一遍。

@Test
public void testPrintHelloWorld() {

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

如果你的工具对 100% 的代码覆盖率不严格,你甚至可以忽略它并证明它是合理的。

Case_2:使用在测试方法中创建并调用另一个方法的对象测试方法

假设您有方法调用 DB 以在 Hello_World 表中添加条目也将其打印在控制台中,如下所示。

public void printHelloWorld() throws DBException {

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

您可以将这些数据库代码提取到新方法中,然后单独测试。

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");
}

在使用 DB 进行测试时,您会期望 DBConnectionException,因为它只是单元测试。因此,使用@Test(expected=DBException) 对makeHelloWorldEntryInTable 进行一项测试,并在printHelloWorld() 上进行另一项测试,并跳过方法makeHelloWorldEntryInTable 调用,如下所示。从而增加代码覆盖率。

@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:如果您有私有方法,则将其设为默认包级别并对其进行测试。从而提高代码覆盖率。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多