Saya telah menulis sebuah pabrik untuk menghasilkan java.sql.Connection
objek:
public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {
@Override public Connection getConnection() {
try {
return DriverManager.getConnection(...);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Saya ingin memvalidasi parameter yang diteruskan ke DriverManager.getConnection
, tetapi saya tidak tahu bagaimana cara mengejek metode statis. Saya menggunakan JUnit 4 dan Mockito untuk test case saya. Apakah ada cara yang baik untuk mengejek / memverifikasi kasus penggunaan khusus ini?
java
unit-testing
mocking
mockito
Naftuli Kay
sumber
sumber
static
metode mengejek , tetapi secara tidak sengaja . Batasan ini (bersama dengan tidak ada dukungan untukfinal
kelas / metode mengejek , ataunew
objek -ed) adalah konsekuensi alami (tetapi tidak disengaja) dari pendekatan yang digunakan untuk mengimplementasikan mengejek, di mana kelas baru secara dinamis dibuat yang mengimplementasikan / memperluas jenis yang akan diejek; perpustakaan mengejek lainnya menggunakan pendekatan lain yang menghindari keterbatasan ini. Ini terjadi di dunia .NET juga.Jawaban:
Gunakan PowerMockito di atas Mockito.
Kode contoh:
Informasi lebih lanjut:
sumber
@RunWith(PowerMockRunner.class)
dan di bawah itu@PowerMockRunnerDelegate(JUnit4.class)
.Strategi khas untuk menghindari metode statis yang tidak bisa Anda hindari, adalah dengan membuat objek terbungkus dan menggunakan objek pembungkus.
Objek pembungkus menjadi fasad ke kelas statis nyata, dan Anda tidak menguji mereka.
Objek pembungkus bisa berupa sesuatu
Akhirnya, kelas Anda yang diuji dapat menggunakan objek tunggal ini dengan, misalnya, memiliki konstruktor default untuk penggunaan kehidupan nyata:
Dan di sini Anda memiliki kelas yang dapat dengan mudah diuji, karena Anda tidak langsung menggunakan kelas dengan metode statis.
Jika Anda menggunakan CDI dan dapat menggunakan anotasi @Inject maka lebih mudah. Cukup buat Wrapper bean Anda @ApplicationScoped, dapatkan benda itu disuntikkan sebagai kolaborator (Anda bahkan tidak perlu konstruktor yang berantakan untuk pengujian), dan teruskan mengejeknya.
sumber
Saya punya masalah serupa. Jawaban yang diterima tidak bekerja untuk saya, sampai saya membuat perubahan :,
@PrepareForTest(TheClassThatContainsStaticMethod.class)
menurut dokumentasi PowerMock untuk mockStatic .Dan saya tidak harus menggunakan
BDDMockito
.Kelasku:
Kelas ujian saya:
sumber
Seperti yang disebutkan sebelumnya Anda tidak dapat mengejek metode statis dengan mockito.
Jika mengubah kerangka kerja pengujian Anda bukan opsi, Anda dapat melakukan hal berikut:
Buat antarmuka untuk DriverManager, tiru antarmuka ini, suntikkan melalui semacam injeksi ketergantungan dan verifikasi pada tiruan itu.
sumber
Pengamatan: Ketika Anda memanggil metode statis dalam entitas statis, Anda perlu mengubah kelas di @PrepareForTest.
Untuk misalnya:
Untuk kode di atas jika Anda perlu mengejek kelas MessageDigest, gunakan
Sedangkan jika Anda memiliki sesuatu seperti di bawah ini:
lalu, Anda harus menyiapkan kelas tempat kode ini berada.
Dan kemudian mengejek metode ini:
sumber
Anda dapat melakukannya dengan sedikit refactoring:
Kemudian Anda dapat memperluas kelas Anda
MySQLDatabaseConnectionFactory
untuk mengembalikan koneksi yang diejek, melakukan pernyataan pada parameter, dll.Kelas yang diperluas dapat berada di dalam test case, jika terletak di paket yang sama (yang saya sarankan Anda lakukan)
sumber
Untuk mengejek metode statis, Anda harus menggunakan tampilan Powermock di: https://github.com/powermock/powermock/wiki/MockStatic . Mockito tidak menyediakan fungsionalitas ini.
Anda dapat membaca artikel yang bagus tentang mockito: http://refcardz.dzone.com/refcardz/mockito
sumber
Mockito tidak dapat menangkap metode statis, tetapi karena Mockito 2.14.0 Anda dapat mensimulasikannya dengan membuat contoh doa metode statis.
Contoh (diekstraksi dari tes mereka ):
Tujuan mereka bukan untuk secara langsung mendukung penghinaan statis, tetapi untuk meningkatkan API publiknya sehingga perpustakaan lain, seperti Powermockito , tidak harus bergantung pada API internal atau secara langsung harus menduplikasi beberapa kode Mockito. ( sumber )
sumber
Saya juga menulis kombinasi Mockito dan AspectJ: https://github.com/iirekm/varia/tree/develop/ajmock
Contoh Anda menjadi:
sumber
Karena metode itu statis, ia sudah memiliki semua yang Anda perlukan untuk menggunakannya, sehingga ia mengalahkan tujuan mengejek. Mengejek metode statis dianggap sebagai praktik yang buruk.
Jika Anda mencoba melakukan itu, itu berarti ada sesuatu yang salah dengan cara Anda ingin melakukan pengujian.
Tentu saja Anda dapat menggunakan PowerMockito atau kerangka kerja lain yang mampu melakukan itu, tetapi cobalah untuk memikirkan kembali pendekatan Anda.
Sebagai contoh: cobalah untuk mengejek / menyediakan objek, yang dikonsumsi oleh metode statis itu.
sumber
Gunakan kerangka kerja JMockit . Ini berhasil untuk saya. Anda tidak perlu menulis pernyataan untuk mengejek metode DBConenction.getConnection (). Hanya kode di bawah ini sudah cukup.
@Mock di bawah ini adalah paket mockit.Mock
sumber