Blog Post #9

Utkarsh
Published: 08/12/2021

In the penultimate week of my GSoC experience, I wrote unit tests and increased coverage for the scripts, namely, pyemail.py, pyqr.py, and pyi25. These scripts added email, QR, and barcode functionality respectively. My work for each of these scripts can be found in PR#94, PR#95, PR#96.

What did I do ?

As mentioned above, my work this week was to write unit tests for the scripts which responsible for email, QR , and barcode services. This week was mostly fun due to the fact that these scripts worked independently and the results were visual. By this I mean that you could see the QR and barcode generated by invoking the scripts and errors could be found more easily and fixed.

PyEmail

This script provided email functionality that could be used to send email to other users using a particular user's Email and password. It made use of smtplib library to make this possible. My work while developing unit tests was to mock this particular library using pytest-mock. This was necessary for testing as we couldn't otherwise check if the service was working properly or not. Therefore just checking if a particular function was invoked could help us to test the service. I wrote the following code to achieve this:-
def test_main_prueba(mocker):

    mocker.patch("smtplib.SMTP")
    sys.argv = [ ]
    sys.argv.append("/prueba")
    sys.argv.append("user@gmail.com")
    sys.argv.append("pass123")
    main()
    smtplib.SMTP.assert_called_with('smtp.gmail.com', 587)

One can easily see that I am using pytest-mock to mock the functionality of smtplib library and just checking if the SMTP fuction is invoked.

PyQR

This script provides QR image generation functionality in this project. Based on the data provided, it can be encoded into the QR image, which when scanned will provide the user with a link or url in this case. To test the script and check if it was working correctly, I compared the QR image generated during testing with a sample QR saved previously. To compare the images, I used Image and ImageChops library:-
def test_main_archivo():
    archivo = "prueba_qr.png"
    sys.argv = []
    sys.argv.append("--archivo")
    sys.argv.append(archivo)
    main()
    assert os.path.exists(archivo)
    #compare the image with a reference one
    if sys.version_info[0] < 3:
        ref = Image.open("tests/images/qr2.png")
    else:
        ref = Image.open("tests/images/qr.png")        
    test = Image.open(archivo)
    diff = ImageChops.difference(ref, test)
    assert diff.getbbox() is None

If one analyzed the code, they could see that I have tested the generated image with different images depending on the python version used. This is due to the fact that since strings are handled differently on both python versions, they lead to a different url being generated for both the python versions. But both URLs lead to the same page.

Pyi25

This script provided barcode functionality to the project and to test the generated barcode I used the same logic as above. ImageChops library is used to compare the pixel wise difference between two images.
def test_GenerarImagen():
    "Prueba de generaciĆ³n de imagen"
    barras = "2026756539302400161203034739042201105299"
    archivo = "prueba.png"
    pyi25.GenerarImagen(barras, archivo)
    assert os.path.exists(archivo)
    #compare the image with a reference one
    ref = Image.open("tests/images/prueba-cae-i25.png")
    test = Image.open(archivo)
    diff = ImageChops.difference(ref, test)
    assert diff.getbbox() is None

Also, two of the scripts, pyqr.py and pyi25.py provided an option to view the QR or barcode generated. Now on windows it's pretty straightforward. We just check if the image file is opened or not since on windows, the code uses os.startfile to open the images. But on linux eog service is required to be installed in order to view the image. So to check if this viewing functionality would work correctly on linux based systems, I mocked the os.system library and checked if it was invoked or not. This is sufficient because we can assume that if the user has eog image viewer installed, everything will work fine.
def test_main_mostrar(mocker):
    mocker.patch("os.system")
    sys.argv = []
    sys.argv.append("--mostrar")
    archivo = "prueba-cae-i25.png"
    main()
    if(sys.platform == 'linux2' or sys.platform == 'linux'):
        os.system.assert_called_with("eog " "%s" "" % archivo)