如何在应用中对带有随机参数的方法进行存根?
如何对controller.sink.add() 的调用进行桩化(存根),以便它接收一个随机输入值?
领域类正在像下面这样调用该方法。
class DomainClass extends ChangeNotifier {
late final DiVariables diVariables;
num answer = 0;
StreamSink<num> get _input => diVariables.streamController.sink;
Stream<num> get outputStream => diVariables.streamController.stream;
DomainClass({required DIVariables diVariablesParam}) {
this.diVariables = diVariablesParam;
calculateOutput(diVariables: diVaririables);
}
int testableRandomInt(num maxNumber) => Random().nextInt(maxNumber.toInt());
Future<void> calculateOutput({required DIVariables diVariables}) {
//calculation of variable to add to stream
var temp = testableRandomInt(diVariables.streamsProcessorList[0]);
_input.add(temp); // add method is called
}
}
class DIVariables {
late final List streamsProcessorList = List.filled(2, null);
final _streamController = StreamController<num>.broadcast();
StreamController<num> get streamController => _streamController;
DIVariables({
required SelectedOperation selectedOperation,
required int stopCount,
required String value,
}) {
this.selectedOperation = selectedOperation;
streamsProcessorList[0] = stopCount;
streamsProcessorList[1] = int.parse(value) + 1;
}
}
现在,这个类在小部件中通过StreamBuilder显示流中的值。
class _NumberScreenState extends State<NumberScreen> {
late DomainClass domainClass;
@override
Widget build(BuildContext context) {
domainClass = DomainClass(
diVariablesParameter: getIt<DIVariables>());
return Scaffold(
body: StreamBuilder<num>(
stream: getIt<DIVariables>().outputStream,
builder: (context, snapshot) {
if((snapshot.connectionState==ConnectionState.active||
snapshot.connectionState==ConnectionState.done)&&
snapshot.hasData) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
snapshot.data.toString(),
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.w800,
),
),
ElevatedButton(
key: const Key('buttonExit'),
child: const Text('Exit'),
onPressed: () {
domainClass.elevatedButtonPress(
()=> Navigator.pop(context,domainClass.answer)
, snapshot);
},
),
],
),
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
}
我有一个小部件测试文件,其中DIVariables类已被模拟,但我无法用测试文件中定义的控制器来替换流,以便让它产生值,而不是使用真实实现。
我正在尝试通过以下AI建议的控制器模拟来测试小部件:
testWidgets('StreamBuilder displays data', (WidgetTester tester) async {
final controller = StreamController<String>();
await tester.pumpWidget(
MaterialApp(
home: StreamBuilder<String>(
stream: controller.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
}
return const Text('Loading');
},
),
),
);
// Initial state
expect(find.text('Loading'), findsOneWidget);
// Emit data
controller.add('Hello');
await tester.pump(); // Trigger rebuild
// Verify updated state
expect(find.text('Hello'), findsOneWidget);
controller.close();
});
此外,我还希望获得帮助,在满足条件时测试CircularProgressIndicator小部件在屏幕上出现的情况,因为在小部件测试文件中无法访问snapshot。
解决方案
Random().nextInt() 不是你这里应该进行桩化的对象。你的testableRandomInt() 方法已经为在需要时覆盖或模拟随机值提供了一个切点。
更大的问题在于DomainClass会从DIVariables创建并使用StreamController,这意味着你的小部件测试无法控制会发出什么。
与其去模拟sink.add(),不如注入依赖。
class DomainClass {
DomainClass({
required this.input,
required this.output,
required this.random,
});
final StreamSink<num> input;
final Stream<num> output;
final Random random;
void calculateOutput(int max) {
input.add(random.nextInt(max));
}
}
那么你的测试就变得直接了当:
final controller = StreamController<num>();
final domain = DomainClass(
input: controller.sink,
output: controller.stream,
random: FakeRandom(), // returns a deterministic value
);
或者简单地由你自己发出值:
controller.add(42);
await tester.pump();
expect(find.text('42'), findsOneWidget);
要测试CircularProgressIndicator,请在第一次pump之前不要发出任何数据:
await tester.pumpWidget(MyWidget());
expect(find.byType(CircularProgressIndicator), findsOneWidget);
controller.add(42);
await tester.pump();
expect(find.byType(CircularProgressIndicator), findsNothing);
expect(find.text('42'), findsOneWidget);
如果你在使用get_it,请在泵送小部件之前注册测试用的DIVariables(包含你的测试StreamController),而不是尝试去模拟StreamSink.add()。一般而言,测试一个真实的StreamController比模拟StreamSink API要容易得多。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。