Showing posts with label Unit Test. Show all posts
Showing posts with label Unit Test. Show all posts

Friday, September 1, 2017

iOS UI Unit Test


You may already be familiar with the concept of Unit Testing. However, usually Unit Tests are done for the logic of the application, but not so much for the visual aspects and the user interaction with the application itself. Making sure the user can interact correctly with the app is as important as what the logic of the app itself does, if not more. So how do we test this?


There are some ways to achieve this in different languages, platforms, and technologies. However, if you are developing a native iOS application, there is a simple and effective way to do it. UI unit testing.


UI unit testing is a kind of unit tests that can interact with the app as a user would, tapping on different elements and triggering gestures to ensure the flow of the app is as expected.


So let’s get started with UI unit testing, by creating our first tests and learning how to run them.



Incorporate UI unit testing to your project



First, let’s start by adding the unit tests to our project. If you are creating a new project from scratch, this is really easy to do. Actually, you don’t even have to do anything! By default, both unit tests and UI unit tests are added to a project when it is created on Xcode. You will see during the creation process that the check boxes corresponding to this tests are already marked:






If you wish to add UI unit testing for an existing project it is not much harder. Just go to File -> New -> Target. On this screen just look for “iOS UI Testing Bundle” and add it to your project. Doing so will add a new folder to your project where all UI tests will be included. Pretty simple!





Creating UI Unit Tests



UI Tests will usually be located in their own folder, which by default will be called “projectNameUITests”. Inside this folder, there should already be a file for UI tests. The class that is defined here uses XCTestCase, and should override both the “setUp” and “tearDown” functions. The first test file should come with some comments that explain what those are, but basically “setUp” is called before each test, and “tearDown” is called after each test. You use them for setting the state of the app where your tests should run and doing the cleanup afterward.


Now we come to the main part of UI Unit Test: the tests themselves. We will create a new function for each test we want to do. Note that all test functions should start with “test” since that is how they are recognized as test functions instead of just auxiliary functions.


To start with, it is recommended that you create a var to reference the app itself on the test class, since this will be used many times to retrieve screen elements. This can be done as following:


class TestExamplesUITests: XCTestCase {
   var app: XCUIApplication!
   override func setUp() {
       super.setUp()
       continueAfterFailure = false
       app = XCUIApplication()
       app.launch()
   }
}


You may notice “continueAfterFailure” in the code above. It pretty much does what it says on the tin. It is a boolean value which determines if a test should continue after it fails (and find everything that fails inside that test), or if it should stop and continue with the other tests.


Now we need to create the tests themselves. As with Unit Tests in general, we will create a certain flow for the test to follow and assert that what should happen has happened. The main difference is that, instead of testing pure logic and assert the results, we will interact with screen elements and assert that the screen is updated accordingly.


Here is a really simple example of a UI Unit Test, in which we will tap a button that is on the first screen (identified as “nextButton”) which should navigate to a second screen, and later check that a label (identified as “nextScreenLabel”) is on screen now that the navigation has been performed.


func testNavigateToNextScreen() {
       XCTAssertTrue(app.buttons["nextButton"].exists)
       XCTAssertFalse(app.staticTexts["nextScreenLabel"].exists)
       app.buttons["nextButton"].tap()
       XCTAssertTrue(app.staticTexts["nextScreenLabel"].exists)
   }


As you see, first we check that the button that we want to press exists. No purpose in continuing our test if there is no button to press, right? After that, we check that the label that should only be on the second screen does not currently exist (test should start in the first screen of the App). Then we tap the button and check again if the label is now present. If everything worked correctly, this test should succeed when we run it.


There are other events we can trigger, like gestures on the App itself. For example, to create a swipe event from the user in the app, we can call app.swipeLeft(). It is that simple!
And now let’s see how to run the test and check the results.



Running tests and checking screenshots



As you’d expect, this is not rocket science.





You just need to go to the tab shown in the image above on Xcode and you will see all tests you have created, UI or otherwise. Now hover over any of the tests (or the entire testing bundle) and a “run” icon will appear. Click on it, and there you go! Just a word of warning, UI tests take much longer to run than other Unit Tests since it has to compile the app an emulate it on real time as a user would. But that is a minor price to pay.


After all selected tests have run, you will get an icon with a tick or an x indicating which of them failed and which of them succeeded.


However, this is not where it ends. We can actually see exactly how the app looked in many steps along the way of each test. Just right click on the test you want to examine more carefully, and click on “Jump to report”. You will see something like the following:




Now you just need to click on the “eye” icon at the right of one of the steps that have it, and you will see a screenshot of the app exactly at that moment of the process. Normally screenshots are taken after each interaction, so you should be able to see everything you need.


And there you have it! Here are the basics of UI Unit Testing on iOS on Swift. You should be able to take this basic tutorial and adapt it to your needs with some minor digging to get the exact interactions you need. We also have an example on our GitHub linked down below of the test done above and one extra test using the swipe interaction. Feel free to check it!


Reference


Friday, June 30, 2017

Python unittest


Unit testing is an automated testing technique used to check small pieces of a project, usually called units. These units are defined by the developer so it can be from a tiny function to a whole functionality. However, there are some basic rules that every single test should follow:
  1. It has to be able to run independently.
  2. It has to run on memory
  3. It has to be consistent (always returns the same result for the same input)
  4. It should be fast
Those rules must be fulfilled to be able to run any unit at any time since it is needed to run the tests properly.
The basic idea of unit testing is to run the test every time the developer makes substantial changes to the code. By doing this you will know if a unit is still working or not after those changes, reducing the time and effort spent on bug fixing.

Unittest

Running simple tests

Unittest is a standard python library, which allows you to define and run tests in an easy way. Let’s start with a very simple example:
from unittest import TestCase, main


class TestBasicArithmeticMethods(TestCase):

    def test_add(self):
        self.assertEqual(2 + 2, 4)

    def test_subtract(self):
        self.assertEqual(3 - 2, 1)

    def test_multiply(self):
        self.assertEqual(3 * 3, 9)

    def test_equal(self):
        self.assertTrue(3 == 3)
        self.assertFalse(2 == 9)

if __name__ == '__main__':
    main()
First things first, what is defined here is a test case, which is the smallest part which can be defined using unittest. The only thing you have to do is defining unittest.TestCase as a superclass.
A test case will look for any method starting with “test_” and run it when you run the test case. Also, if you want to define only one test you can override the runTest method, which is the simplest way to do it.
The "if" statement at the bottom runs the tests every time you compile the code, which is very useful to check that recently added code does not change the correct functionality, as it was mentioned in the introduction.

Loading information

These tests are really simple and don’t need additional information to work, but in some cases, you need to load data from disk. Loading information every time you need it is inefficient and, as it was said before, the tests should run fast.
For that matter, unittest implement the setUp and tearDown methods, which allows you to load information before the tests, and then erase it after they are executed. Here you have an example:
from unittest import TestCase, main

from complex import Complex



class TestComplexArithmetic(TestCase):

    def setUp(self):
        self.zero = Complex()

    def test_add_complex(self):
        one_onei = Complex(1, 1)
        result = one_onei + self.zero
        self.assertEqual(result.r, 1)
        self.assertEqual(result.i, 1)

    def test_sub_complex(self):
        one_onei = Complex(1, 1)
        result = self.zero - one_onei
        self.assertEqual(result.r, -1)
        self.assertEqual(result.i, -1)

    def tearDown(self):
        del self.zero
As you can see here, the setUp method defines a private attribute called zero, which is used on all of the test cases. Then, that value is deleted after all the test cases are finished.
In this case, the zero value could be defined in every case because it isn’t a time-consuming operation, it is just added as an example. In general, in the setUp method, you will make queries to a database or pre-process information. Then, it will delete that information on the tearDown method to avoid filling the memory up with unnecessary data.

Skipping tests

Sometimes it is necessary to skip some tests after they are checked, for example, if they take a lot of resources, or if they are not supported by older libraries.
In that cases, you can use the unittest decorators skip and skipIf. The first decorator receives optional parameters only, where the most important is the message shown when the test is skipped. The second one needs a boolean value to check if the test is skipped or not, and then optionally the message. Let’s see an example:
from unittest import TestCase, skip, skipIf

from complex import Complex


class TestComplexArithmetic(TestCase):

    def setUp(self):
        self.zero = Complex()

    @skip("Sure that this is correct, and will never change")
    def test_default_complex_value(self):
        self.assertEqual(self.zero.r, 0)
        self.assertEqual(self.zero.i, 0)

    @skipIf(Complex.__version__ < (1, 1), "Not supported by this library")
    def test_equal_complex(self):
        zero = Complex()
        one = Complex(1)
        self.assertTrue(zero == self.zero)
        self.assertFalse(self.zero == one)

    def tearDown(self):
        del self.zero
On this example, you can see that the first test is always skipped with the skip decorator, which is used in general for time-consuming tests that have already been passed. Then the second test is skipped for older versions of the library, very useful when you use libraries in development or different libraries depending on the virtual environment.
Congratulations! You now have all the tools to do unit testing on your Python projects.
You can check a sample project here.