I have two models: book
and review
.
In book.dart
, I have a field to list down the reviews (defined in review.dart
) associated with this book.
class Book {
final String id;
final String bookid;
final String title;
final String author;
final DateTime purchDate;
final String intro;
final List<Review> reviews;
Book(this.id, this.bookid, this.title, this.author, this.purchDate,
this.intro, this.reviews);
Book.fromJson(Map<String, dynamic> json)
: id = json['id'].toString(),
bookid = json['bookid'],
title = json['title'],
author = json['author'],
purchDate = DateTime.parse(json['purchdate']),
intro = json['intro'],
reviews = json['reviews'];
}
And this is the review.dart
:
class Review {
final int id;
final String title;
final DateTime datein;
final String uri;
Review(this.id, this.title, this.datein, this.uri);
Review.fromJson(Map<String, dynamic> json)
: id = json['id'],
title = json['title'],
datein = DateTime.parse(json['datein']),
uri = json['URI'];
}
The unit test for review
model works fine.
However, when I tried to run a unit test for book
model:
import 'dart:convert';
import 'package:test/test.dart';
import 'package:rsywx/model/book.dart';
import 'package:http/http.dart' as http;
void main() {
test('Retrieve a book with review(s)', () async {
var uri = 'https://api';
var res = await http.get(Uri.parse(uri));
var result = jsonDecode(res.body)['data'];
var book = Book.fromJson(result);
expect(book.id, '666');
expect(book.author, '卡尔维诺');
expect(book.reviews.length, 2);
expect(book.reviews[0] is Map<String, dynamic>, true);
expect(book.reviews[1] is Map<String, dynamic>, true);
});
}
An error occurs:
00:04 0 -1: Retrieve a book with review(s) [E]
type 'List<dynamic>' is not a subtype of type 'List<Review>'
package:rsywx/model/book.dart 22:17 new Book.fromJson
test/book_test.dart 13:21 main.<fn>
I understand that from my http.get
and jsonDecode
, the result
has no way to determine or show that the field reviews
is actually a List<Reviews>
. So the error appears.
I can eliminate this particular error by changing the book
model definition, in particular: from List<Review> reviews
to List<dynamic> reviews
. But I want to have a stronger type control.
Thanks for the help.
CodePudding user response:
in book.dart
class Book {
final String id;
final String bookid;
final String title;
final String author;
final DateTime purchDate;
final String intro;
final List<Review> reviews;
Book(this.id, this.bookid, this.title, this.author, this.purchDate,
this.intro, this.reviews);
Book.fromJson(Map<String, dynamic> json)
: id = json['id'].toString(),
bookid = json['bookid'],
title = json['title'],
author = json['author'],
purchDate = DateTime.parse(json['purchdate']),
intro = json['intro'],
reviews = (json['reviews'] as List).map((e)=>Review.fromdynamic(e)).toList();
}
in review.dart
class Review {
final int id;
final String title;
final DateTime datein;
final String uri;
Review(this.id, this.title, this.datein, this.uri);
Review.fromdynamic(dynamic json)
: id = json['id'],
title = json['title'],
datein = DateTime.parse(json['datein']),
uri = json['URI'];
}
CodePudding user response:
@Ye Myo Aung's answer is fine. But I would recommend to avoid dynamic type parameters. So I would change Review's named constructor to:
Review.fromJson(Map<String, dynamic> json)
: id = json['id'],
title = json['title'],
datein = DateTime.parse(json['datein']),
uri = json['URI'];
And the the Book's fromJson it changes to:
Book.fromJson(Map<String, dynamic> json)
: id = json['id'].toString(),
bookid = json['bookid'],
title = json['title'],
author = json['author'],
purchDate = DateTime.parse(json['purchdate']),
intro = json['intro'],
reviews = (json['reviews'] as List)
.map((e) => Review.fromJson(e as Map<String, dynamic>))
.toList();