我一直在阅读和探索Perl中单元测试和测试驱动开发的概念.我正在研究如何将测试概念融入我的开发中.假设我在这里有一个Perl子程序:
sub perforce_filelist { my ($date) = @_; my $path = "//depot/project/design/...module.sv"; my $p4cmd = "p4 files -e $path\@$date,\@now"; my @filelist = `$p4cmd`; if (@filelist) { chomp @filelist; return @filelist; } else { print "No new files!" exit 1; } }
子例程执行Perforce命令并将该命令的输出(这是文件列表)存储到@filelist数组中.这个子程序可以测试吗?测试返回的@filelist是否为空有用吗?我试图教自己如何像单位测试开发人员一样思考.
解决方法
有一些事情使得测试perforce_filelist子例程比它需要的更难:
> p4路径是硬编码的
> p4命令在子例程中构造
> p4命令是固定的(因此,它始终是路径中的第一个p4)
>直接从子程序输出
>您从子程序内退出
但是,您的子程序的职责是获取文件列表并将其返回.除此之外你做的任何事情都会让你更难测试.如果由于你无法控制,你无法改变这一点,你可以在将来编写这样的东西:
#!perl -T # Now perforce_filelist doesn't have responsibility for # application logic unrelated to the file list my @new_files = perforce_filelist( $path,$date ); unless( @new_files ) { print "No new files!"; # but also maybe "Illegal command",etc exit 1; } # Now it's much simpler to see if it's doing it's job,and # people can make their own decisions about what to do with # no new files. sub perforce_filelist { my ($path,$date) = @_; my @filelist = get_p4_files( $path,$date ); } # Inside testing,you can mock this part to simulate # both returning a list and returning nothing. You # get to do this without actually running perforce. # # You can also test this part separately from everything # else (so,not printing or exiting) sub get_p4_files { my ($path,$date) = @_; my $command = make_p4_files_command( $path,$date ); return unless defined $command; # perhaps with some logging my @files = `$command`; chomp @files; return @files; } # This is where you can scrub input data to untaint values that might # not be right. You don't want to pass just anything to the shell. sub make_p4_files_command { my ($path,$date) = @_; return unless ...; # validate $path and $date,perhaps with logging p4() . " files -e $path\@$date,\@now"; } # Inside testing,you can set a different command to fake # output. If you are confident the p4 is working correctly,# you can assume it is and simulate output with your own # command. That way you don't hit a production resource. sub p4 { $ENV{"PERFORCE_COMMAND"} // "p4" }
但是,您还必须判断这种分解水平是否值得.对于不经常使用的个人工具,可能工作量太大.对于你必须支持并且很多人使用的东西,它可能是值得的.在这种情况下,您可能需要official P4Perl API.这些价值判断取决于您.但是,在分解问题后,进行更大的更改(例如使用P4Perl)不应该像地震一样.
作为旁注而不是我推荐的这个问题,这是& amp;的用例.并没有参数列表.在这个“加密上下文”中,子程序的参数列表是调用它的子程序的@_.
这些调用继续在链中传递相同的参数,这很难输入和维护:
my @new_files = perforce_filelist( $path,$date ); my @filelist = get_p4_files( $path,$date ); my $command = make_p4_files_command( $path,$date );
随着&并且没有参数列表(不是偶数()),它将@_传递到下一个级别:
my @new_files = perforce_filelist( $path,$date ); my @filelist = &get_p4_files; my $command = &make_p4_files_command;