code

JUnit으로 Java에서 추상 클래스를 테스트하는 방법은 무엇입니까?

codestyles 2020. 9. 24. 07:52
반응형

JUnit으로 Java에서 추상 클래스를 테스트하는 방법은 무엇입니까?


JUnit으로 Java 테스트를 처음 사용합니다. Java로 작업해야하고 단위 테스트를 사용하고 싶습니다.

내 문제는 : 일부 추상 메서드가있는 추상 클래스가 있습니다. 그러나 추상적이지 않은 방법이 있습니다. JUnit으로이 클래스를 어떻게 테스트 할 수 있습니까? 예제 코드 (매우 간단 함) :

abstract class Car {

    public Car(int speed, int fuel) {
        this.speed = speed;
        this.fuel = fuel;
    }

    private int speed;
    private int fuel;

    abstract void drive();

    public int getSpeed() {
        return this.speed;
    }

    public int getFuel() {
        return this.fuel;
    }
}

테스트 getSpeed()하고 getFuel()기능 하고 싶습니다 .

이 문제에 대한 비슷한 질문이 여기 에 있지만 JUnit을 사용하지 않습니다.

JUnit FAQ 섹션 에서이 링크를 찾았 지만 저자가이 예제에서 무엇을 말하고 싶은지 이해가되지 않습니다. 이 코드 줄은 무엇을 의미합니까?

public abstract Source getSource() ;

클래스의 구체적인 구현이없고 메서드가 static테스트의 요점 이 아니라면 ? 구체적인 클래스가있는 경우 해당 메서드를 구체적인 클래스의 공용 API의 일부로 테스트하게됩니다.

나는 당신이 "내가 추상 클래스를 만든 이유 때문에이 메서드들을 계속해서 테스트하고 싶지 않다"라고 생각하는 것을 알고 있지만, 이에 대한 나의 반론은 단위 테스트의 요점이 개발자가 변경할 수 있도록하는 것입니다. 테스트를 실행하고 결과를 분석합니다. 이러한 변화의 일부는 추상 클래스의 메소드를 오버라이드 (override) 포함, 모두 수 protectedpublic근본적인 행동 변화를 초래할 수있는. 이러한 변경 사항의 특성에 따라 응용 프로그램이 예상치 못한 방식으로 실행되는 방식에 영향을 미칠 수 있습니다. 좋은 단위 테스트 스위트를 가지고 있다면 이러한 유형 변경으로 인해 발생하는 문제는 개발시에 분명해야합니다.


추상 클래스를 상속하는 구체적인 클래스를 만든 다음 해당 추상 클래스에서 상속되는 함수를 테스트합니다.


게시 한 예제 클래스를 사용하면 테스트하는 것이별로 이치에 맞지 않는 것 같 getFuel()으며 getSpeed()0 만 반환 할 수 있기 때문입니다 (세터가 없음).

그러나 이것이 설명을위한 단순한 예제 일 뿐이고 추상 기본 클래스에서 메서드를 테스트 할 합법적 인 이유가 있다고 가정하면 (다른 사람들은 이미 의미를 지적 했음) 익명을 생성하도록 테스트 코드를 설정할 수 있습니다. 추상 메서드에 대한 더미 (no-op) 구현 만 제공하는 기본 클래스의 하위 클래스입니다.

예를 들어 다음과 같이 TestCase할 수 있습니다.

c = new Car() {
       void drive() { };
   };

그런 다음 나머지 방법을 테스트합니다. 예 :

public class CarTest extends TestCase
{
    private Car c;

    public void setUp()
    {
        c = new Car() {
            void drive() { };
        };
    }

    public void testGetFuel() 
    {
        assertEquals(c.getFuel(), 0);
    }

    [...]
}

(이 예제는 JUnit3 구문을 기반으로합니다. JUnit4의 경우 코드가 약간 다르지만 아이디어는 동일합니다.)


If you need a solution anyway (e.g. because you have too many implementations of the abstract class and the testing would always repeat the same procedures) then you could create an abstract test class with an abstract factory method which will be excuted by the implementation of that test class. This examples works or me with TestNG:

The abstract test class of Car:

abstract class CarTest {

// the factory method
abstract Car createCar(int speed, int fuel);

// all test methods need to make use of the factory method to create the instance of a car
@Test
public void testGetSpeed() {
    Car car = createCar(33, 44);
    assertEquals(car.getSpeed(), 33);
    ...

Implementation of Car

class ElectricCar extends Car {

    private final int batteryCapacity;

    public ElectricCar(int speed, int fuel, int batteryCapacity) {
        super(speed, fuel);
        this.batteryCapacity = batteryCapacity;
    }

    ...

Unit test class ElectricCarTest of the Class ElectricCar:

class ElectricCarTest extends CarTest {

    // implementation of the abstract factory method
    Car createCar(int speed, int fuel) {
        return new ElectricCar(speed, fuel, 0);
    }

    // here you cann add specific test methods
    ...

You could do something like this

public abstract MyAbstractClass {

    @Autowire
    private MyMock myMock;        

    protected String sayHello() {
            return myMock.getHello() + ", " + getName();
    }

    public abstract String getName();
}

// this is your JUnit test
public class MyAbstractClassTest extends MyAbstractClass {

    @Mock
    private MyMock myMock;

    @InjectMocks
    private MyAbstractClass thiz = this;

    private String myName = null;

    @Override
    public String getName() {
        return myName;
    }

    @Test
    public void testSayHello() {
        myName = "Johnny"
        when(myMock.getHello()).thenReturn("Hello");
        String result = sayHello();
        assertEquals("Hello, Johnny", result);
    }
}

I would create a jUnit inner class that inherits from the abstract class. This can be instantiated and have access to all the methods defined in the abstract class.

public class AbstractClassTest {
   public void testMethod() {
   ...
   }
}


class ConcreteClass extends AbstractClass {

}

You can instantiate an anonymous class and then test that class.

public class ClassUnderTest_Test {

    private ClassUnderTest classUnderTest;

    private MyDependencyService myDependencyService;

    @Before
    public void setUp() throws Exception {
        this.myDependencyService = new MyDependencyService();
        this.classUnderTest = getInstance();
    }

    private ClassUnderTest getInstance() {
        return new ClassUnderTest() {    
            private ClassUnderTest init(
                    MyDependencyService myDependencyService
            ) {
                this.myDependencyService = myDependencyService;
                return this;
            }

            @Override
            protected void myMethodToTest() {
                return super.myMethodToTest();
            }
        }.init(myDependencyService);
    }
}

Keep in mind that the visibility must be protected for the property myDependencyService of the abstract class ClassUnderTest.

You can also combine this approach neatly with Mockito. See here.


My way of testing this is quite simple, within each abstractUnitTest.java. I simply create a class in the abstractUnitTest.java that extend the abstract class. And test it that way.


You can not test whole abstract class. In this case you have abstract methods, this mean that they should be implemented by class that extend given abstract class.

In that class programmer have to write the source code that is dedicated for logic of his.

In other words there is no sens of testing abstract class because you are not able to check the final behavior of it.

If you have major functionality not related to abstract methods in some abstract class, just create another class where the abstract method will throw some exception.


As an option, you can create abstract test class covering logic inside abstract class and extend it for each subclass test. So that in this way you can ensure this logic will be tested for each child separately.

참고URL : https://stackoverflow.com/questions/7569444/how-to-test-abstract-class-in-java-with-junit

반응형