web-dev-qa-db-ja.com

JUnitでJavaの抽象クラスをテストするには?

私はJava JUnitでテストするのは初めてです。私は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()関数をテストしたい。

この問題と同様の質問は here ですが、JUnitを使用していません。

JUnit FAQセクションで、私は このリンク を見つけましたが、著者がこの例で何を言いたいのか理解できません。このコード行はどういう意味ですか?

_public abstract Source getSource() ;
_
80
vasco

クラスの具体的な実装がなく、メソッドがstaticではない場合、それらをテストするポイントは何ですか?具象クラスがある場合、具象クラスのパブリックAPIの一部としてこれらのメソッドをテストします。

「これらのメソッドを何度もテストしたくないので抽象クラスを作成したい」とあなたが考えていることはわかっていますが、それに対する私の反論は、単体テストのポイントは開発者が変更を行えるようにすることであり、テストを実行し、結果を分析します。これらの変更の一部には、抽象クラスのメソッド(protectedpublicの両方)のオーバーライドが含まれる可能性があり、これにより基本的な動作の変更が発生する可能性があります。これらの変更の性質によっては、アプリケーションの予期しない、おそらくはネガティブな方法での実行方法に影響を与える可能性があります。優れた単体テストスイートを使用している場合、これらのタイプの変更から生じる問題は、開発時に明らかになります。

104
nsfyn55

抽象クラスを継承する具象クラスを作成し、具象クラスが抽象クラスから継承する機能をテストします。

31
Kevin Bowersox

あなたが投稿したクラスの例では、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の場合、コードは少し異なりますが、考え方は同じです。)

12
Grodriguez

とにかく解決策が必要な場合(たとえば、抽象クラスの実装が多すぎて、テストが常に同じ手順を繰り返すため)、その実装によって実行される抽象ファクトリメソッドを持つ抽象テストクラスを作成できます。テストクラス。この例は、TestNGで動作します。

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);
    ...

Carの実装

class ElectricCar extends Car {

    private final int batteryCapacity;

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

    ...

クラスElectricCarTestの単体テストクラス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
    ...
9
thomas.mc.work

このようなことができます

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);
    }
}
5
iil

抽象クラスから継承するjUnit内部クラスを作成します。これはインスタンス化でき、抽象クラスで定義されたすべてのメソッドにアクセスできます。

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


class ConcreteClass extends AbstractClass {

}
3
marting

匿名クラスをインスタンス化し、そのクラスをテストできます。

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

可視性は、抽象クラスprotectedのプロパティmyDependencyServiceClassUnderTestでなければならないことに注意してください。

また、このアプローチをMockitoときれいに組み合わせることができます。 here を参照してください。

2
Samuel

これをテストする私の方法は、各abstractUnitTest.Java。 abstractUnitTest.Javaに抽象クラスを拡張するクラスを作成するだけです。そして、そのようにテストします。

1
Haomin

抽象クラス全体をテストすることはできません。この場合、抽象メソッドがあります。つまり、特定の抽象クラスを拡張するクラスによって実装する必要があります。

そのクラスでは、プログラマは自分のロジック専用のソースコードを記述する必要があります。

つまり、抽象クラスの最終的な動作を確認できないため、抽象クラスをテストする意味はありません。

何らかの抽象クラスの抽象メソッドに関連しない主要な機能がある場合は、抽象メソッドが例外をスローする別のクラスを作成するだけです。

オプションとして、抽象クラス内のロジックをカバーする抽象テストクラスを作成し、サブクラステストごとに拡張できます。このようにして、このロジックが各子に対して個別にテストされるようにすることができます。

0
Andrew Taran