Flutterexperts

Empowering Vision with FlutterExperts' Expertise
Unit Testing In Flutter

Hello everyone, I am back with another interesting topic- Unit Testing in Flutter

So today, I will talk about, unit testing in flutter and give you some examples that you would be able to implement in your apps to test them for better performance in every aspect.


First focus on why testing in flutter is much, much better than testing on IOS or Android native code,

Well for once if you have any experience with UI Automator or Espresso, you might’ve noticed how much time taking they are, They are quite slow and prone to break easily, In-fact many times you would end up searching in your code for what did you mess up while it might just not be your fault,

Not only they are more expensive to run but there is also flakiness in it.

OK, so now let me tell you why flutter’s testing is amazing

(every time I think I cannot fall in love with flutter anymore, It just proves me wrong)

So, Unit Testing, are the type of tests are usually conducted to test a particular method or a class under variety of cases. These tests do not require inputs and don’t have anything to do with rendering anything to screen or even reading/ writing from the disk. These are the simplest tests to perform .

So to perform these we use test statements something like 
test(‘i m testing this feature’) and then you write your code and after that write the expect statement which is basically what you “expect” the code to do.

(the best example I can think of for this is like imagine if you are making a D&D game and well you have a function that generates a random number and according to that number reads out a scenario)

Alright, so now we have studied about Unit Testing lets see how is it done.

So first we move over to test directory in our project

After that we need to import the package

import 'package:flutter_test/flutter_test.dart';

So When you are done importing the flutter test package you need to create void main() and then follow as i do :

void main() {

test('title for your test', (){
// your function body
int a;
int b =5;
int c = 5;
a =b + c;
expect(a, 10);
});
}

So, what we have here is a simple test, earlier I told about how tests are created now we are going to have a detailed look at it and see what is it doing.

so the test keyword is from flutter_test package which helps us test stuff, if takes 2 parameters, first is a String aka the title of your test, the other is basically a function and inside that function you put out what you wanna test

After you are done writing the body of your function now you need to write your expect which is basically what you expect this test to do, so in this case I put in my a at the place of “actual” and then at the place of “matcher” I put in the value I expect a to have when the function ends, simple right?

Now then how do we run tests?

So after writing the test you might’ve noticed a run button next to number of the line you wrote test keyword

So clicking on that will run the test and in the logs you can see whether the test failed or passed

Alright so now we can move on to testing better stuff, so currently I am making a D&D game so I want to put some dialogue when players rolls the dice and lands on a particular number

so to test it, I created a new class called Dialogue and in the class I made a static function that returns dialogue based on what the user rolled,

class Dialogue {
static String dialoguePicker(int val) {
switch(val) {
case 1:
return "You rolled 1, You earned 500 gems, brave adventurer!";
break;
case 2:
return "You rolled 2, You now have to face a monster and win!";
break;
case 3:
return "You rolled 3, You get an extra life, adventurer!";
break;
case 4:
return "You rolled 4, You get a brand new sword brave adventurer!";
break;
case 5:
return "You rolled 5, You get a new shield brave adventurer!";
break;
case 6:
return "You rolled 6, You get a Full HP health potion!";
break;
default:
return " I am sorry adventurer we have ran out of goods at the moment";
}
}
}

So its a simple switch that decides what my NPC says. now lets try to test it out

Right so when you have multiple tests that belong to a particular group its called grouping of tests, so to group them you have to use group keyword which takes a String as title and a function as body

void main() {

group("testing the dialogue generated by user's roll", (){
test("test when user lands 1", () {
int val = 1;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 1, You earned 500 gems, brave adventurer!");
});

test("test when user lands 2", () {
int val = 2;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 2, You now have to face a monster and win!");
});

test("test when user lands 3", () {
int val = 3;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 3, You get an extra life, adventurer!");
});

test("test when user lands 4", () {
int val = 4;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 4, You get a brand new sword brave adventurer!");
});

test("test when user lands 5", () {
int val = 5;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 5, You get a new shield brave adventurer!");
});

test("test when user lands 6", () {
int val = 6;
String dialogue = Dialogue.dialoguePicker(val);
expect(dialogue, "You rolled 6, You get a Full HP health potion!");
});
});


}

So here is the full function, now to run this you just need to click on the run button near the group.

Tests are also useful for situations like when you have a validations class and have to test the response of several validations such as validateEmpty or validateEmail etc.

Now that, that’s done for let’s try something a little more interesting, something everyone has to make in their app — Validations

Now in the lib folder we will create another file called validations, and paste below this piece of code

class Validation {

static String validateEmpty(String val) {
if(val.isEmpty) {
return "the value cannot be empty";
}
else {
return null;
}
}

static String validateEmail(String val) {
if(val.isNotEmpty) {
bool emailValid = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(val);
return emailValid?null:"please enter a valid email address";
}
else {
return "email cannot be left empty";
}
}

static String validatePassword(String val) {
if(val.isNotEmpty) {
String pattern = r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!@#\$&*~]).{8,}$';
bool passVerified = new RegExp(pattern).hasMatch(val);
return passVerified?null:"please enter a correct password";
}
else {
return "passwords cannot be left empty";
}

}
}

Its just a simple class that helps you do validations and returns error message if there is any, Now in this case there are 3 methods,

  1. validateEmpty — to check for any empty values in a textfield
  2. validateEmail — to check for any incorrect values entered in the email textfield
  3. validatePassword — to check that the password entered appropriate

Now to test them we will once again create a group and inside that group we will test, first of all the 1. case of validateEmpty only 2 times, once for checking the it return error and the other for checking in case of no error

so first case would be written like this :

test("test field empty returns error", () {
String result = Validation.validateEmpty("");
expect(result, "the value cannot be empty");
});

and the second case goes like this :

test("test field not empty returns null", () {
String result = Validation.validateEmpty("asd");
expect(result, "the value cannot be empty");
});

Then we will test validateEmail 3 times, once for correct value, second for incorrect value and third for empty

First case :

test("test user input email correctly  returns null", () {
String result = Validation.validateEmail("test@gmail.com");
expect(result, null);
});

Second case :

test("test user input email incorrectly returns error", () {
String result = Validation.validateEmail("test@gmail.com");
expect(result, "please enter a valid email address");
});

Final case :

test("test user not entering email returns error", () {
String result = Validation.validateEmail("");
expect(result, "email cannot be left empty");
});

And now we will test the validatePassword method 3 times as well, where all the cases would be same as validateEmail — correct value,incorrect value, empty

First case :

test("test user entering password correctly returns null", () {
String result = Validation.validatePassword("Pass@123");
expect(result, null);
});

Second case :

test("test user entering password incorrectly returns error", () {
String result = Validation.validatePassword("asddsaasdsda");
expect(result, "please enter a correct password");
});

Final case :

test("test user not entering password returns error", () {
String result = Validation.validatePassword("");
expect(result, "passwords cannot be left empty");
});
  • And since these test belong to the same class we can group them together under “validation tests”.
  • To test non static methods inside the test() you can easily create the instance of the class inside the test() and use it to conduct the tests you wish.
  • The tests written in Unit Testing must be to the point and not very complex so please remember these things when writing tests.

Feel free to connect with us:
And read more articles from FlutterDevs.com.

FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, Twitter, and LinkedIn for any flutter related queries.

We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.

Leave comment

Your email address will not be published. Required fields are marked with *.