Testing Javascript Apps (with Jest)

Testing Javascript Apps (with Jest)

Bu yazımda react uygulamalarının testleri ile alakalı konulara değineceğim.

Peki niye testlere ihtiyaç duyarız? Neden test yapmalıyız?

Cevabı aslında hepinizin de tahmin edebileceği gibi testler bizim uygulamamızın çalıştığını onaylayan sorgulamalardır diyebiliriz.

Test Türleri

Aşağıda test türleri ve bu testleri hangi kütüphaneleri kullanarak yapabileceğimiz ile ilgili fikir veren bir resim bırakıyorum. Burada olmayan farklı mühendislik yöntemleri kullanılarak oluşturulmuş test türleri de var tabi. Fakat günümüzde frontend uygulamaların da kullanılan genel test türleri bunlardır.

Unit Tests

  • Unit testler tek bir şeyi test ederler. Aşağıda, örnekte ki gibi sonuçları alıp kullandığımız testler unit testlerdir.

Integration Tests

  • Integration testler ise 2 fonksiyonun işleminin aynı anda calışması gereken durumlarda yapılan testlerdir.

End to End (e2e) Tests

  • End to end testlerde ise test yapılacak siteyi açıp, kullanıcının siteyi görüp kullandığı gibi testleri yazabiliriz. Aşağıda bunu yaptığımız bir cypress testi görüyoruz. Cypress bu alanda kullanılan popüler kütüphanelerden birisidir.

NOT: Testlerimiz kullanıcının yapacağı işlemleri test etmelidir. Gereksiz yere, işe yaramayacak kısımlar için test yazmak doğru değildir. Örnek olarak, sitemizin footer alanında yazan, “Copyright” yazan elementi seçip, textContent’inin “Copyright”’a eşit olduğunu test etmek mantıksızdır.

Bazı Terimler

  • Methods: expect, toBe, not, gibi testlerimizin sonuçlarını doğrulamamıza izin veren javascript fonksiyonlarıdır. Matcher diye de çağrılırlar.
  • Mocking: Fake, taklit eden yapılardır. Örneğin mock bir function veya request oluşturarak bunların kaç kere çağrıldığını, ne ile kullanıldığını gibi varyasyonlarla test edebiliyoruz.
  • Lifecycle: Javascript framwork ve librarylerinde olduğu gibi testlerimizde de kullanabildiğimiz, her testten önce, sonra, tüm testlerden önce, sonra gibi işlevsellikler sunan test yapılarıdır. Bunlar kısaca:

Lifecycle Methods

beforeEach: Her test işleminden önce

afterEach: Her test işleminden sonra

beforeAll: Tüm test işlemlerinden önce

afterAll: Tüm test işlemlerinden sonra

Jest

  • İlk başta React uygulamalarını test etmek için ortaya çıksada, daha sonraları Javascript uygulamalarını test edebildiğimiz bir yapıya dönüşen test kütüphanesidir.
  • Hiçbir ayar gerekmeksizin testlerimizi yapabiliriz ve ayarları oldukça basit bir yapıdadır.
  • Terminalden testlerimizi takip edebileceğimiz güzel bir yapısı vardır.
  • Güzel bir documentationu vardır.

Kurulum

  • Aşağıdaki kod ile jest’i install ediyoruz.

npm install — save-dev jest

  • Daha sorna package.json dosyamıza aşağıda ki script’i ekliyoruz.

“test”: “jest”

  • Ve artık aşağıda ki kod ile testimizi çalıştırabiliriz. Bu kod çalıştığında root dizininde bulunan tüm .spec.js veya .test.js dosyalarını bulur ve çalıştırır.

npm run test

Test Dosya Yapısı

describe: Testlerimizi içinde toplayarak gruplandırdığımız methoddur. İlk argumenti, gruplandırılan testlerin tanımıdır, ikinci argumentde testlerimizin olduğu ve çalıştığı fonksiyondur. Aşağıda örnek bir describe yapısı bırakıyorum.

it / test: Her bir testimizi bu method içinde tanımladığımız methoddur. it ve test her ikisi de aynıdır. İkisinden birisini kullanabilirsiniz. Örnek olarak yukarıdaki kodlara bakabilirsiniz.

  • .skip: Kullanıldığı testi skip eder. Yani test etmez. Bazen mesela tüm testleri yapsın fakat 1 tane testi yapmasın istediğimiz durumlarda testi kısaca bu kodla pasif hale geçirebiliriz.

  • .only: Bunu kullandığımız da ise tüm testleri yoksayar ve test açlıştığında sadece .only olan testi yapar.

METHODS (Methods for tests with Jest)

  • Matcherları en iyi öğrenebileceğiniz yer jestin kendi documentation’udur.

[***expect(value)***](https://jestjs.io/docs/en/expect.html#expectvalue)

  • İçine argument olarak verdiğimiz değerin kontrolünü yapmamızı sağlar.

[***.toBe(value)***](https://jestjs.io/docs/en/expect.html#tobevalue)

  • Açık ara en çok testlerde kullanılan matcherdır.
  • Javascript’teki primitive(string, number, boolean) değerlerin kontrol etmemizi sağlar.
  • Kısaca bir primitive değerin ne olduğunu sorgulamamızı sağlar.

Yukarıda ki iki matcher’ı burada ki örnek ile açıklamak istiyorum. expect ile total değişkenini almışız ve diyoruz ki expect yani ümit et, yani total’i kontrol et, daha sonra toBe ile olmalı diyoruz. Peki ne olmalı? toBe içine verdiğimiz argument olmalı.

[***.toEqual(value)***](https://jestjs.io/docs/en/expect.html#toequalvalue)

  • Objelerin ve arraylerin referans olarak değilde içerik olarak aynı olup olmadığını sorgular. Yani bir car birde television adında 2 değişken objemiz olsun. Bunların marka ve ücretleri olsun. Eğer ikisininde markası ve ücreti aynıysa bu 2 obje birbirinin aynısı olacağı için toEqual testten geçer.

[***.toBeTruthy()***](https://jestjs.io/docs/en/expect.html#tobetruthy) ***/*** [***.toBeFalsy()***](https://jestjs.io/docs/en/expect.html#tobefalsy)

  • Expect edilen değerin true veya false olduğunu kontrol ederiz.

[***.not***](https://jestjs.io/docs/en/expect.html#not)

  • Tüm matcherları olumsuz olarak test eder veya tersi şeklinde test eder. not.toBe(9) 9 polmamalı gibi.

[***.toContain(item)***](https://jestjs.io/docs/en/expect.html#tocontainitem)

  • Arrayin içindeki elemanların bir değeri içerip içermediğini kontrol eder.

[***.toThrow(error?)***](https://jestjs.io/docs/en/expect.html#tothrowerror)

  • Bir fonksiyonun bir şey throw edip etmediğini kontrol eder.

[***.toBeGreaterThan(number | bigint)***](https://jestjs.io/docs/en/expect.html#tobegreaterthannumber--bigint)

  • Expect içine aldığı değerin, toBeGeaterThan içine aldığı number veya bigInt değerinden büyük olduğunu denetler.

[***.toBeNull()***](https://jestjs.io/docs/en/expect.html#tobenull)

  • Expect edilen değer null ise test geçer.

[***.toBeUndefined()***](https://jestjs.io/docs/en/expect.html#tobeundefined)

  • Expect edilen değer undefined ise test geçer.

JEST CLI

https://jestjs.io/docs/en/cli

  • Daha önce kurulum aşamasında yapacağımız şekilde, en basit haliyle jest cli’ı çalıştırabiliriz. Fakat farklı cli komutlarıda bulunmaktadır. Burada onların bazı önemli olanlarına değineceğim.

— watch

  • normalde yukarıda ki gibi bir kurulumda test dosyalarınızda değişiklik yaptığınız zaman yapılan değişikliği görüp jest tekrardan testi çalıştırmaz. Bunu yapabilmemiz için yukarıdaki — watch kodunu scriptteki jest’ten sonrasına aşağıdaki gibi eklememiz gerekmektedir.

“test”: “jest — watch”

— coverage

  • Testlerimizin kapsama oranlarını görebileceğimiz koddur. Örnek olarak elimizde bir Ödeme utilty dosyası veya komponenti var. Bu dosyaya yaptığımız testin yüzdesel olarak ne kadarını kapsadığını bize gösteren jestin yardımcı özelliğidir diyebiliriz. Terminalde biz bu coverage oranlarını görebilir ve takip edebiliriz.

jest.fn() — MOCK FUNCTIONS

  • Taklit etme yeteneğine sahip fonksiyonlardır diyebiliriz. Ne işimize yarar derseniz, testlerde fonksiyonların kaç kere çağrıldığını, hangi argumentler kullanılarak çağrıldığını test etmemize yarar.

[***.toHaveBeenCalledTimes(number)***](https://jestjs.io/docs/en/expect.html#tohavebeencalledtimesnumber)

  • Bir fonksiyonun kaç kere çağrıldığını test etmemize yarar. Aşağıda expect içine aldığımız add fonksiyonunun, expecte gelene kadar 1 kere çağrıldığını test ediyoruz.

[***.toHaveBeenCalledWith(arg1, arg2, ...)***](https://jestjs.io/docs/en/expect.html#tohavebeencalledwitharg1-arg2-)

  • Bir fonksiyonun hangi argumentler ile çağrıldığını test etmemizi sağlar. Aşağıda expect ile add’i 1 ve 8 argumentleriyle çağırıp, daha sonra .toBe(9) olmalı demişiz. Bu sayede add bir kere çağrıldı. Daha sonra bunu kontrol etmek istersek, expect’e “expect(add)” bu şekilde add’i argument olarak verip daha sonra add ile daha önce kullandığımız argumentleri(1,8) bu sefer toHaveBeenCalledWith ile kullanarak test edeceğiz.

jest.mock() — MOCKs

  • Burada da taklit eden mock yapılar kuruyoruz. Varsayalım ./add.js dosyasından add adında bir ekleme fonksiyonunu dosyamıza dahil edeceğiz. Fakat bu add.js farklı servislerle bağlantılı olduğu için direkt add.js’i dahil etmek ve testlerle kullanmak mantıklı değil, o zaman jest.mock methodu bize yardıma koşuyor.

add.js

  • İlk önce add metodunu ./add.js yolundan import ediyoruz.
  • Daha sonra jest.mock ile mock yapımızı oluşturuyoruz. İlk argument olarak import edilen add dosyasının yolunu veriyoruz ki, taklit edeceği adresi bilebilsin. İkinci argument olarakda bir Object return eden bir fonksiyon oluşturuyoruz.
  • Bu return olan objedeki key, ./add’den import ettiğimiz add gibi, default exportla export edilen bir method gibi değilde, sadece export edilmiş bir değer olarak düşünebilirsiniz.
  • Bu 2. argumentde dönen add adında bir key oluşturuyoruz çünkü add importunu taklit ve manipüle etmesini istiyoruz. ve karşısına value olarakda bir ject.fn ile mock function oluşturuyoruz. Daha sonrası ise şuana kadar gördüğümüz diğer methodlarla işimizi test etmek oluyor.

Daha fazla kafanızı karıştırmamak için bu yazımı burada sonlandırıyorum. Bir sonra ki yazımda burada öğrendiklerimizle Jest’i kullanarak ve diğer kısımda öğreneceğimiz react-testing-library’i kullanarak React Component testlerimizi yapacağız. Bir sonra ki yazımda görüşmek üzere.