繁体   English   中英

私有方法的 Junit 测试用例

[英]Junit Test Case for private method

我有以下课程。 我是编写 junit 测试的新手。 我需要为此编写测试用例。 如何在测试类中为startSchemaMaintenance方法编写测试方法,因为它正在调用没有参数的私有方法?

public class SchemaMaintenance {

    //Loading statuses overview
    // NOT_STARTED = 0
    // START_LOADING = 1
    // IN_PROGRESS = 2
    // COMPLETED = 3
    // LOADING_ERROR = 4
    private static volatile Integer loading_status = 0;

    public void startSchemaMaintenance() throws Exception {
        if (checkLoadingStatus() == 1) {
            doSchemaMaintenance();

            loading_status = 3;
        }
    }

    private void doSchemaMaintenance(){
        //Do something....
    }

    private int checkLoadingStatus() throws Exception {
        if (loading_status==0 ||loading_status == 2) {
            synchronized (loading_status) {
                if (loading_status==0) {
                    loading_status = 2;
                    return 1;
                }else if(loading_status == 2) {
                    while(loading_status == 2);

                    if((loading_status == 4)){

                        throw new Exception("status = " + 4);
                    }
                }else if(loading_status == 4) {

                    //log.error(generateErrorMessage());
                    throw new Exception("status = " + 4);
                }
            }
        }else if((loading_status == 4)){
            //log.error(generateErrorMessage());
            throw new Exception("status = " + 4 );
        }

        return loading_status;

    }
}

首先有几点:

  1. 为什么 loading_status 是静态的? 基本上这个类的 2 个实例将使用相同的 loading_status 变量。 loading_status 不应该是静态的,或者 checkLoadingStatus 也应该是静态的。
  2. loading_status 的名字很糟糕。 如果您想保持静态,您应该将其命名为 LOADING_STATUS。 如果它不是静态的,我们将其命名为 loadingStatus。 这是Java约定。
  3. 您应该为 loading_status 创建一个合适的枚举类型,而不是一个整数。
  4. while (loading_status == IN_PROGRESS); 只是不好的做法。 至少你可以做的是: while(loading_status == IN_PROGRESS) { Thread.sleep(100); }; while(loading_status == IN_PROGRESS) { Thread.sleep(100); }; 然而,超时是更好的做法。 类似的东西:
long timeoutMillis = 5000L; // Should come from a configuration or something
long endTimeMillis = System.currentTimeMillis() + timeoutMillis;
while (loadingStatus == IN_PROGRESS) {
    long remainingMillis = end - System.currentTimeMillis();
    if (remaining <= 0) {
        // Timeout while loading
        loadingStatus = LOADING_ERROR;
        break;
    }
    Thread.sleep(50);
}
// ...

最后,我猜有些事情会将 loadingStatus 更新为已完成或其他内容。 我猜你也在那里使用同步。 如果加载发生在 2 个不同的线程上,那么您最终将陷入死锁。 如果 checkLoadingStatus 先进入同步块,那么当加载完成时加载线程将永远无法进入同步块,因为 checkLoadingStatus 正在保持锁。

最后但并非最不重要的是回答你的问题,如果你想保持你的方法私有,你可以通过反射调用它,但这又是一种不好的做法。 通常,您应该避免对私有方法进行单元测试,并对调用它的方法进行单元测试。 但是,如果您确实需要对特定方法进行单元测试,请将其设为包私有而不是私有,然后您可以在包含您的方法的类所在的同一个包中创建单元测试。 并且您可以向该方法添加注释,说明它仅对单元测试可见。 在这种情况下您的代码结构示例:

src
+-- main
+-- +-- com/app/MyClass.java
+-- test
    +-- com/app/MyClassTest.java // this test class will able to access package-private methods in MyClass

通常,当您无法测试您的代码时,您应该考虑重写它,使其可测试。 私有方法不能以常规方式在您的类之外调用,甚至不能在 JUnit 测试中调用。

您可以做一些事情来使其可测试:

  1. 重写您的代码以将方法拆分为更小的方法。 应始终在适当的情况下进行。

  2. 您可以将方法包设为私有(删除私有修饰符),以便您的测试类(必须在同一个包中)可以访问它。

  3. 您可以使方法受保护,因此您可以在测试中继承您的类,并通过继承的类间接调用该方法。

  4. 您可以调用一个方法,该方法调用该方法,您想测试并相应地做出断言。

如果您倾向于将方法的可见性更改为包私有或受保护,您可以将您的方法注释为@VisibleForTesting ,以便像 Sonar 和其他团队成员这样的工具知道为什么它不是私有的。

希望能帮助到你。

您的私有方法根​​据内部私有变量loading_status值工作,因此在您的测试中,您应该能够更改该变量。 为此,您可以执行以下操作:

package com.test

import com.test.SchemaMaintenance;
import org.junit.Test;
import org.mockito.internal.util.reflection.Whitebox;

public class SchemaMaintenanceTest {

    @Test
    public void TestSchema() throws Exception {
        SchemaMaintenance schema = new SchemaMaintenance();
        Whitebox.setInternalState(schema,"loading_status",2);
        schema.startSchemaMaintenance();
    }

}

假设您应该在项目中包含mockito依赖项:

例如 Maven

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>1.6.4</version>
</dependency>

这是一种对我有用的方法。

  1. 在您的班级中创建一个公共“测试员”内部班级。
    • 如果您正在测试内部类,则“测试人员”仍然需要在外部类上。
  2. 测试人员是您要测试的私有方法的代表。
  3. 向您的类添加一个方法以获取测试器的实例
  4. 在您的测试方法中获取测试器的一个实例并
  5. 通过适当的测试器实例方法调用您的私有方法。

根据所需的方法和内部类等的访问,会有不同的变化。

这个例子不能有静态“测试器”,因为我们需要测试非静态内部类中的方法。

//  Outer owner class
//
public class OwnerClass Class {
    
    private class InnerClass {
            : 
            
        //  method I'm testing
        //
        private void doSomething)( String name ){
            ...
        }
    }
    
        :
    
    //  Tester class
    //
    public class InnerClassTester {
        
        private final InnerClass        innerClass    = new InnerClass();
            :
            
        //  test invocatiion
        //
        private void doSomething)( String name ){
            
            innerClass.doSomething)( name )
        }
    }

    //  Get an instance of the tester
    //    
    public InnerClassTester getInnerClassTester() {
        return new InnerClassTester();
    }

在你的单元测试里面......

@Test
public void doSomethingTest() throws Exception {
    
    OwnerClass ownerClass = new OwnerClass();
    innerClassTester      = ownerClass.InnerClassTester();
            :
            
    //  Test the private method
    //
    innerClassTester.doSomething( "123456" );
}

与调试器一起使用。 您需要根据您的访问灵活地定义测试器和测试器获取器。 测试仪也可能受到protected ,我没有尝试过。 一切顺利。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM