mirror of
https://github.com/nisrulz/flutter-examples.git
synced 2025-08-24 06:21:52 +08:00
Example for Unit Test (#52)
This commit is contained in:
72
unit_testing/lib/api/Places.dart
Normal file
72
unit_testing/lib/api/Places.dart
Normal file
@ -0,0 +1,72 @@
|
||||
import 'package:unit_testing/model/lat_long.dart';
|
||||
import 'package:unit_testing/model/location.dart';
|
||||
|
||||
class PlacesAPI {
|
||||
final List<Location> _locations = [
|
||||
Location(
|
||||
id: 1,
|
||||
name: "Kumarakom Backwaters",
|
||||
country: "India",
|
||||
info: "Kerala’s scenic backwaters, "
|
||||
"edged with coconut palms, "
|
||||
"lush green rice paddies and picturesque villages,"
|
||||
"make for a beautiful escape from hectic city life.",
|
||||
image: "assets/1.jpeg",
|
||||
latlong: LatLong(
|
||||
latitude: 9.9540358,
|
||||
longitude: 76.2671037,
|
||||
),
|
||||
),
|
||||
Location(
|
||||
id: 2,
|
||||
name: "Angel Falls",
|
||||
country: "Venezuela",
|
||||
info: "Venezuela overflows with natural wonders, "
|
||||
"including the world's highest waterfall—the 3,212-foot cascades of Angel Falls,"
|
||||
" located in the UNESCO-protected Canaima National Park. "
|
||||
"Canaima is by far the country's most popular attraction,"
|
||||
" and the falls stretch an astounding 19 times higher than Niagara Falls. ",
|
||||
image: "assets/2.jpg",
|
||||
latlong: LatLong(
|
||||
latitude: 5.9689135,
|
||||
longitude: -62.5376132,
|
||||
),
|
||||
),
|
||||
Location(
|
||||
id: 3,
|
||||
name: "Avenue of the Baobabs",
|
||||
country: "Madagascar",
|
||||
info:
|
||||
"Separated from continental Africa by 250 miles of water, Madagascar "
|
||||
"is the greatest adventure"
|
||||
" you haven't had yet. The island nation's secrets include giant moths, "
|
||||
"bug-eyed lemurs, and places like the surreal Avenue of the Baobabs,"
|
||||
" where the centuries-old trees reach heights of nearly 100 feet.",
|
||||
image: "assets/3.jpg",
|
||||
latlong: LatLong(
|
||||
latitude: -20.2498059,
|
||||
longitude: 44.4172047,
|
||||
),
|
||||
),
|
||||
Location(
|
||||
id: 4,
|
||||
name: "Denali National Park",
|
||||
country: " Alaska",
|
||||
info: "Despite controversies over name changes and a shrinking elevation,"
|
||||
" Denali's beauty is worth braving the extreme low temperatures. Make a "
|
||||
"road trip out of your visit, seeing as "
|
||||
"much of the 6 million acres of shimmering lakes and jagged mountains as you can.",
|
||||
image: "assets/4.jpg",
|
||||
latlong: LatLong(
|
||||
latitude: 63.2092486,
|
||||
longitude: -152.2366999,
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
Future<List<Location>> fetchAllPlaces() {
|
||||
return Future.delayed(Duration(seconds: 3), () {
|
||||
return _locations;
|
||||
});
|
||||
}
|
||||
}
|
55
unit_testing/lib/components/place_info_card.dart
Normal file
55
unit_testing/lib/components/place_info_card.dart
Normal file
@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:unit_testing/model/location.dart';
|
||||
|
||||
class PlaceInfo extends StatelessWidget {
|
||||
final Location data;
|
||||
PlaceInfo({this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.all(20),
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
offset: Offset(0, 10),
|
||||
blurRadius: 20,
|
||||
color: Colors.black45,
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
data.name + "\n" + data.country,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Image.asset(
|
||||
data.image,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
data.info,
|
||||
style: TextStyle(fontSize: 23),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
33
unit_testing/lib/helpers.dart
Normal file
33
unit_testing/lib/helpers.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:unit_testing/api/Places.dart';
|
||||
import 'package:unit_testing/model/location.dart';
|
||||
|
||||
class TouristPlaces {
|
||||
static Future<List<Location>> getData() async {
|
||||
// Here we can call a real API.
|
||||
return await PlacesAPI().fetchAllPlaces();
|
||||
}
|
||||
}
|
||||
|
||||
class FormValidator {
|
||||
static String validateEmail(String email) {
|
||||
final pattern = RegExp(
|
||||
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
|
||||
if (email.isEmpty) {
|
||||
return "please enter email";
|
||||
} else if (!pattern.hasMatch(email)) {
|
||||
return "please enter valid email";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String validatePassword(String password) {
|
||||
if (password.isEmpty) {
|
||||
return "please enter your password";
|
||||
} else if (password.length < 8) {
|
||||
return "minimum lenght of password must be 8 characters";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
20
unit_testing/lib/main.dart
Normal file
20
unit_testing/lib/main.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:unit_testing/screens/home_screen.dart';
|
||||
import 'package:unit_testing/screens/sign_in_screen.dart';
|
||||
|
||||
void main() => runApp(MyApp());
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Material App',
|
||||
initialRoute: "/",
|
||||
routes: {
|
||||
"/": (context) => SignInScreen(),
|
||||
"/homeScreen": (context) => HomeScreen(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
5
unit_testing/lib/model/lat_long.dart
Normal file
5
unit_testing/lib/model/lat_long.dart
Normal file
@ -0,0 +1,5 @@
|
||||
class LatLong {
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
LatLong({this.latitude, this.longitude});
|
||||
}
|
18
unit_testing/lib/model/location.dart
Normal file
18
unit_testing/lib/model/location.dart
Normal file
@ -0,0 +1,18 @@
|
||||
import 'lat_long.dart';
|
||||
|
||||
class Location {
|
||||
final int id;
|
||||
final String name;
|
||||
final String image;
|
||||
final LatLong latlong;
|
||||
final String country;
|
||||
final String info;
|
||||
Location({
|
||||
this.id,
|
||||
this.name,
|
||||
this.image,
|
||||
this.latlong,
|
||||
this.country,
|
||||
this.info,
|
||||
});
|
||||
}
|
39
unit_testing/lib/screens/home_screen.dart
Normal file
39
unit_testing/lib/screens/home_screen.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:unit_testing/components/place_info_card.dart';
|
||||
import 'package:unit_testing/model/location.dart';
|
||||
|
||||
import '../helpers.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
@override
|
||||
_HomeScreenState createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Unit Test'),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: FutureBuilder(
|
||||
future: TouristPlaces.getData(), // this functions calls API.
|
||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final List<Location> data = snapshot.data;
|
||||
return ListView.builder(
|
||||
physics: BouncingScrollPhysics(),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (context, index) => PlaceInfo(
|
||||
data: data[index],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
60
unit_testing/lib/screens/sign_in_screen.dart
Normal file
60
unit_testing/lib/screens/sign_in_screen.dart
Normal file
@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:unit_testing/helpers.dart';
|
||||
|
||||
class SignInScreen extends StatefulWidget {
|
||||
@override
|
||||
_SignInScreenState createState() => _SignInScreenState();
|
||||
}
|
||||
|
||||
class _SignInScreenState extends State<SignInScreen> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(40.0),
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.account_circle,
|
||||
size: 200,
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
TextFormField(
|
||||
validator: (value) => FormValidator.validateEmail(value),
|
||||
decoration: InputDecoration(
|
||||
hintText: "Email",
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
TextFormField(
|
||||
validator: (value) => FormValidator.validatePassword(value),
|
||||
decoration: InputDecoration(
|
||||
hintText: "Password",
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 50,
|
||||
),
|
||||
RaisedButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
Navigator.of(context).pushReplacementNamed('/homeScreen');
|
||||
}
|
||||
},
|
||||
child: Text('Sign In'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user