Mock Kavramı ve GoogleMock (gMock) Nedir/Nasıl Kullanılır?

Birim (Unit) testleri yazarken sadece kendi içerisinde statik olarak uygulanan algoritmalarla çalışmayız, hatta çoğu zaman bu şekilde çalışmayız. Onun yerine diğer objelerle sürekli etkileşimde olan, gerçek zamanlı (real time) olarak işlemler gerçekleştiren şekilde tasarımlar yaparız. Benzer sistem tasarımlarının testlerini yazarken de her zaman gerçek objeler üzerinde çalışamayız. İşte tam olarak burada karşımıza kurtarıcı niteliğinde bir kavram çıkıyor, Mocking.

Mock kavramı anlamı itibarı ile taklit objeler oluşturmamıza izin vermektedir. Gerçek zamanlı testlerde karşılaşacağımız objelerin taklit edilen hallerini oluşturarak testimize dahil etmemize yarar. Bu yazıda üzerinde işlem gerçekleştireceğimiz Mock framework‘ü ise GoogleMock (gMock) olacak. Yazı içerisindeki anlatımların bir çoğunu YouTube kanalımda anlattığım GoogleTest video serisi içerisinden de ulaşabilirsiniz (Henüz yayınlanmadı).

Mock objeleri ile diğer diller üzerinde çalışırken sizin için işin bir kısmını otomatikleştiren araçlar olduğunu görebilirsiniz. GoogleMock (gMock) da C++ dili özelinde bu işi yapan bir araç olarak Google tarafından tasarlanmıştır. Kullanılacak olan komponentin arayüz üzerindeki davranışlarını tespit etmek için kullanılırlar.


GoogleMock Nasıl Kullanılır?

Bu konudaki en özenle hazırlanmış ve detaylı kaynak olarak Google‘ın kendi dokümantasyonunu örnek verebiliriz. İlgili linklere “Kaynaklar” kısmında ulaşabilirsiniz.

Bir örnek üzerinden anlatmaya çalışacağım ancak öncesinde bilmemiz gerekenlerden kısaca bahsetmek istiyorum. Mock nesneleri içerisinde MOCK_METHOD fonksiyonu ile tanımlamalar yapacağız. Fonksiyonun aldığı parametreler:

  • MOCK_METHOD(void, FonksiyonAdi_1, (), (override));
  • MOCK_METHOD(void, FonksiyonAdi_2, (int parameter_1, int param_2), (override));
  • MOCK_METHOD(int, FonksiyonAdi_3, (), (const, override));

Böyle bir yazımda şunu ifade etmektedir; ilk parametre sizin taklit objeniz üzerinde test etmek için oluşturduğunuz fonksiyonunuzun geri dönüt tipi, ikinci parametre fonksiyon adınız, 3. parametre eğer fonksiyonumuz içerisine bir parametre gönderiyorsak o parametrelerin verilmesi gerekiyor, eğer girilmiyor ise boş gönderilebilir. 4. parametrede ise fonksiyonunuz sabit metot ile kullanılıyorsa belirtilmesi gerekir. Eski versiyon kullanımlarda MOCK_METHOD yerine tercih edilen bir diğer kullanım daha vardır:

  • MOCK_METHOD0(FonksiyonAdi_1)
  • MOCK_METHOD1(FonksiyonAdi_2, void(int parameter_1)) // sadece bir parametre aldığı zaman kullanılır
  • MOCK_METHOD2(FonksiyonAdi_2, void(int parameter_1, int parameter_2)) // sadece iki parametre aldığı zaman kullanılır
  • MOCK_CONST_METHOD1(FonksiyonAdi_2, void(int parameter_1)) // const metodu içerdiği zaman kullanılır

5 parametre alan bir fonksiyon için MOCK_METHOD5 makrosu kullanılmalıydı yani kaç parametre varsa sondaki sayı onunla değişmeliydi ancak eğer 10+ parametre alan bir fonksiyonumuz varsa yalnızca MOCK_METHOD10 makrosu kullanılırdı. Yazının ilerleyen bölümlerinde yeni makroyu kullanacağım.

Mock kullanımı esnasında karşımıza ON_CALL ve EXPECT_CALL makroları çıkıyor. ON_CALL makrosu bir testin kaç kez yapıldığı sizin için önemli değilse kullanabileceğiniz bir makro ancak prototip ve kullanım itibari ile EXPECT_CALL ile aynı yapıya sahiptir, EXCEPT_CALL’dan farklı olarak sadece With() ve WillByDefault() fonksiyonları ile birlikte kullanılabilir.

EXPECT_CALL tanımlaması kullanacağımız mock testlerinin vazgeçilmezidir. Ve:

  • With(multi-argument-matchers)
  • Times(cardinality)
  • InSequence(sequences)
  • After(expectations)
  • WillOnce(action)
  • WillRepeatedly(action)
  • RetiresOnSaturation();

fonksiyonları ile birlikte kullanılır. Tanımlamasını yaptığımız fonksiyon çağırıldığında nasıl tepki vereceğini belirtmemizi ister. Yani aşağıdaki gibi bir kullanım yaptığımız zaman;

EXPECT_CALL(obje_adi, getValueFromObject())
    .Times(10)
    .WillOnce(Return(130))
    .WillOnce(Return(140))
    .WillOnce(Return(150))
    .WillRepeatedly(Return(200));

getValueFromObject() fonksyionunu 10 kez çağıracak, ilk çağırmada 130, ikincisinde 130, üçüncüsünde 150 ve sonrasında her seferinde 200 değerini döndürmesini bekliyoruz. Ana hatları ile kullanılacak olan fonksiyonların ne yaptığına bakacak olursak;

  • With(): içerisine girilecek parametre fonksiyonu da yapılacak işleme dahil eder
  • Times(): çalışması beklenen fonksiyonun kaç kez çalıştırılacağını belirtir
  • InSequence(): belirtilen çağrıların istediğiniz sıraya göre yapılmasını istiyorsanız bir sekans oluşturup ardından fonksiyon içerisinde belirtmeniz gerekmektedir
  • After(): çalışma sonrasında beklenen çıktı için kullanılır
  • WillOnce(): 1 kez çalışması sonucunda ortaya çıkacak çıktıyı belirtir
  • WillRepeatedly(): sürekli çalışması sonucunda ortaya çıkacak çıktıyı belirtir
  • RetiresOnSaturation(): istenilen çıktı oluşmadı ancak fonksiyon çalışabileceği en maksimum noktaya kadar çalıştıysa – saturasyon noktası – fonksiyonu sonlandırır

Burada yazılanlar GoogleMock sisteminin ana yapısını oluştursa da bir miktar havada kaldığının farkındayım. Onun için bu özelliklerin birkaç tanesini bir örnek üzerinde kullanarak daha rahat anlamanızı sağlamaya çalışacağım.

Örnek üzerinde GoogleMock

Aşağıda yer alan örnekte basit bir UserInterface sınıfı oluşturarak onun üzerindeki get/set fonksiyonlarını test edecek bir taklit sınıfı oluşturduk. Bu sayede bir arayüze ihtiyac duymadan otomatik olarak testlerimizi gerçekleştirmiş olduk.

Kodlara bakacak olursak ilk olarak test edilmesini istediğimiz sınıfımızı oluşturduk, daha sonra da bu sınıftan türemiş bir mock sınıfı oluşturduk. Ardından get/set fonksiyonlarımızın nasıl çalıştığını görmek için bir DataReminder sınıfı oluşturduk ve bunlara bağlı testlerimizi yazmaya başladık.

EXPECT_CALL içerisinde çağırdığımız fonksiyonlarımız sayesinde DataReminder içerisinde tutulmasını beklediğimiz veriyi oluşturmuş olduk. Son olarak da kontrollerimizi yaparak testin başarıyla tamamlandığını görmüş olduk.

Kaynaklar

https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md

https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md

http://donsoft.io/gmock-presentation

Richard Wells – Test-Driven Development in C++/ https://www.linkedin.com/learning/test-driven-development-in-c-plus-plus/add-items-add-item-prices-and-calculate-the-current-total

Kapak Görseli: C++ Unit Testing: Google Test and Google Mock / Udemy – https://www.udemy.com/course/cplusplus-unit-testing-google-test-and-google-mock/