Saya baru mengenal pengujian Java dengan JUnit. Saya harus bekerja dengan Java dan saya ingin menggunakan pengujian unit.
Masalah saya adalah: Saya memiliki kelas abstrak dengan beberapa metode abstrak. Tetapi ada beberapa metode yang tidak abstrak. Bagaimana cara menguji kelas ini dengan JUnit? Kode contoh (sangat sederhana):
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;
}
}
Saya ingin menguji getSpeed()
dan getFuel()
berfungsi.
Pertanyaan serupa untuk masalah ini ada di sini , tetapi tidak menggunakan JUnit.
Di bagian FAQ JUnit, saya menemukan tautan ini , tetapi saya tidak mengerti apa yang ingin penulis katakan dengan contoh ini. Apa maksud baris kode ini?
public abstract Source getSource() ;
java
junit
abstract-class
vasco
sumber
sumber
Jawaban:
Jika Anda tidak memiliki implementasi konkret dari kelas dan metodenya bukan
static
apa gunanya mengujinya? Jika Anda memiliki kelas konkret maka Anda akan menguji metode tersebut sebagai bagian dari API publik kelas beton.Saya tahu apa yang Anda pikirkan "Saya tidak ingin menguji metode ini berulang-ulang, itulah alasan saya membuat kelas abstrak", tetapi argumen balasan saya adalah bahwa tujuan pengujian unit adalah untuk memungkinkan pengembang membuat perubahan, menjalankan tes, dan menganalisis hasilnya. Bagian dari perubahan tersebut dapat mencakup menimpa metode kelas abstrak Anda,
protected
danpublic
, yang dapat mengakibatkan perubahan perilaku mendasar. Bergantung pada sifat perubahan tersebut, hal itu dapat memengaruhi bagaimana aplikasi Anda berjalan dengan cara yang tidak terduga dan mungkin negatif. Jika Anda memiliki masalah suite pengujian unit yang baik yang timbul dari jenis perubahan ini harus terlihat pada waktu pengembangan.sumber
final
? Saya tidak melihat alasan untuk menguji metode yang sama beberapa kali jika penerapannya tidak dapat diubahBuat kelas konkret yang mewarisi kelas abstrak lalu uji fungsi yang diwarisi kelas beton dari kelas abstrak.
sumber
Dengan kelas contoh yang Anda posting, tampaknya tidak masuk akal untuk menguji
getFuel()
dangetSpeed()
karena mereka hanya dapat mengembalikan 0 (tidak ada penyetel).Namun, dengan asumsi bahwa ini hanyalah contoh yang disederhanakan untuk tujuan ilustrasi, dan bahwa Anda memiliki alasan yang sah untuk menguji metode dalam kelas dasar abstrak (orang lain telah menunjukkan implikasinya), Anda dapat mengatur kode pengujian Anda sehingga menciptakan anonim subclass dari kelas dasar yang hanya menyediakan implementasi dummy (tanpa operasi) untuk metode abstrak.
Misalnya, dalam diri Anda,
TestCase
Anda dapat melakukan ini:c = new Car() { void drive() { }; };
Kemudian uji metode lainnya, misalnya:
public class CarTest extends TestCase { private Car c; public void setUp() { c = new Car() { void drive() { }; }; } public void testGetFuel() { assertEquals(c.getFuel(), 0); } [...] }
(Contoh ini didasarkan pada sintaks JUnit3. Untuk JUnit4, kodenya akan sedikit berbeda, tetapi idenya sama.)
sumber
Jika Anda tetap membutuhkan solusi (misalnya karena Anda memiliki terlalu banyak implementasi dari kelas abstrak dan pengujian akan selalu mengulangi prosedur yang sama) maka Anda dapat membuat kelas pengujian abstrak dengan metode pabrik abstrak yang akan dieksekusi dengan implementasi tersebut kelas tes. Contoh ini berfungsi atau saya dengan TestNG:
Kelas tes abstrak dari
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); ...
Implementasi dari
Car
class ElectricCar extends Car { private final int batteryCapacity; public ElectricCar(int speed, int fuel, int batteryCapacity) { super(speed, fuel); this.batteryCapacity = batteryCapacity; } ...
Kelas uji unit
ElectricCarTest
KelasElectricCar
: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 ...
sumber
Anda bisa melakukan sesuatu seperti ini
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); } }
sumber
Saya akan membuat kelas dalam jUnit yang mewarisi dari kelas abstrak. Ini dapat dipakai dan memiliki akses ke semua metode yang ditentukan di kelas abstrak.
public class AbstractClassTest { public void testMethod() { ... } } class ConcreteClass extends AbstractClass { }
sumber
Anda dapat membuat instance kelas anonim dan kemudian menguji kelas itu.
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); } }
Perlu diingat bahwa visibilitas harus
protected
untuk propertimyDependencyService
kelas abstrakClassUnderTest
.Anda juga dapat menggabungkan pendekatan ini secara rapi dengan Mockito. Lihat disini .
sumber
Cara saya menguji ini cukup sederhana, di masing-masing
abstractUnitTest.java
. Saya hanya membuat kelas di abstractUnitTest.java yang memperluas kelas abstrak. Dan uji seperti itu.sumber
Anda tidak dapat menguji seluruh kelas abstrak. Dalam hal ini Anda memiliki metode abstrak, ini berarti metode tersebut harus diimplementasikan oleh kelas yang memperluas kelas abstrak yang diberikan.
Di kelas itu programmer harus menulis kode sumber yang didedikasikan untuk logikanya.
Dengan kata lain, tidak ada gunanya menguji kelas abstrak karena Anda tidak dapat memeriksa perilaku akhirnya.
Jika Anda memiliki fungsionalitas utama yang tidak terkait dengan metode abstrak di beberapa kelas abstrak, buat saja kelas lain di mana metode abstrak akan mengeluarkan beberapa pengecualian.
sumber
Sebagai opsi, Anda dapat membuat kelas pengujian abstrak yang mencakup logika di dalam kelas abstrak dan memperluasnya untuk setiap pengujian subclass. Sehingga dengan cara ini Anda bisa memastikan logika ini akan diuji untuk setiap anak secara terpisah.
sumber