生成“伪视频”丰富自动测试日志系统 3

 新方案关键代码解释

        清单一: 实现代码中的主要属性

        //单件模式,用来储存截图的缓冲区。
        private static Vector bufferVec = null;
        //标识缓冲区是否储存固定数目的截图,默认为固定数目。
        private boolean isLimitedBuffer = true;
        //伪视频所覆盖的自动测试过程,单位为秒;默认情况下存储最近30秒内的截图。
        private int videoLength = 30;
        //截图的时间间隔,单位为秒;默认情况下每隔1秒执行一次抓屏操作。
        private double snapInterval = 1;
        //缓冲区容量,该属性值由videoLength和snapInterval共同决定。
        private int bufferCapability;
        //伪视频输出位置
        private String outputLocation = "c:/";
        //伪视频格式,即生成的动态图片格式,在本例给出的实现使用了GIF格式。
        private String pseudoVideoFormat = ".gif";
        //标识生成的伪视频是否循环播放,默认为只播放一次。
        private boolean replayIndefinitely = false;
        //伪视频的重放速度,可选值为1,2,3。分别表示快速、中速和慢速。
        private int replaySpeed = 2;
        //标识是否有错误发生。当其值为true时,表明需要立即生成伪视频。
        public static boolean errorFlag = false;

        清单二: 实现代码中的主要方法

        /*
        * Create a screenshot pool with limited capability, it only
        * stores enough screenshots to create a pseudo-video of appointed length *
        * @param videoLength - length of pseudo-video
        * @param snapInterval - interval to scratch screenshots, the unit is second
        * @param replayIndefinitely - the video plays once or repeats indefinitely
        * @param replaySpeed - play speed of the video,1 means fast,2 is normal,and 3 means slow
        */
            public ScreenshotsPool(int videoLength, double snapInterval,
            boolean replayIndefinitely, int replaySpeed)
             {
                super();
                this.isLimitedBuffer = true;
                this.videoLength = videoLength;
                this.snapInterval = snapInterval;
                this.replayIndefinitely = replayIndefinitely;
                //设置有效的回放速度;
                if((replaySpeed==1)||(replaySpeed==2)||(replaySpeed==3))
                    this.replaySpeed = replaySpeed;
                //通过伪视频长度videoLength和抓屏频率snapInterval计算出缓冲区的容量
                this.bufferCapability = new Double(videoLength/snapInterval).intValue();
                //初始化缓冲区
                getBufferVec();
             }

        ScreenshotsPool方法为构造器,按照给定的参数对必要的属性进行初始化,并初始化唯一的缓冲区。

         /*
        * * Get buffer pool that store screenshots
        * * @return Vector - the only buffer pool to store screenshots
        */
            public Vector getBufferVec()
            {
                if(null==bufferVec)
                    bufferVec = new Vector(bufferCapability);
                return bufferVec;
            }

        getBufferVec()方法是单件模式,用来获得唯一的截图缓冲区;如果缓冲区暂时还不存在,则进行初始化。

         /*
        *  Push a new screenshot into buffer
        *  if the buffer is limited and has reached its capability, the oldest
        *  snapshot would be removed
        */
            public void pushScreenshot()
            {
                //获得当前屏幕的截图对象
                BufferedImage image = getCurrentScreen();
                if(null==image)
                return;
                //如果截图缓冲区有固定容量,
                if(isLimitedBuffer){
                //如果已经到达缓冲区的最大容量,则删去第一副截图
                int size = getBufferVec().size();
                if(size==bufferCapability)
                getBufferVec().remove(0);
                }
                //将当前截图存入缓冲区
                getBufferVec().add(image);
             }

pushScreenshot方法用来将当前屏幕的截图存入缓冲区内。如果截图数目到达缓冲区上限,最早的截图会被删除。

         /*
        *  Get current screenshot
        *  @return BufferedImage - screenshot of current screen
        */
            public BufferedImage getCurrentScreen()
            {
                try{
                    //获得屏幕大小
                    Dimension screenSize = toolkit.getDefaultToolkit().getScreenSize();
                    int width = screenSize.width;
                    int height = screenSize.height;
                    BufferedImage capture = null;
                    //获得当前屏幕范围
                    Rectangle area = new Rectangle(0, 0, width, height);
                    Robot robot = new Robot();
                    //截取当前屏幕范围内的内容,返回BufferedImage对象
                    capture = robot.createScreenCapture(area);
                    return capture;
                    }
                catch (Exception e)
                 {
                    e.printStackTrace();
                    return null;
                 }
            }

        getCurrentScreen方法用来获得当前屏幕的截图,返回值是一个包含当前屏幕图像的BufferedImage对象。

         /*
        * Generate pseudo-video with those buffered screens in pool
        * Here we will generate animated picture of '.gif' format, and we can
        * generate animated picture of other formats likewise.(SVG, PNG, etc.)
        */
            public void generatePseudoVideo()
            {
                int size = this.getBufferVec().size();
                if(size<1)
                return;
                try
                {
                    BufferedImage bi = null;
                    //新建一个AnimatedGifEncoder对象,用来生成动态的GIF文件
                    AnimatedGifEncoder pseudoVideoGenerator = new AnimatedGifEncoder();
                    //设置GIF文件是否循环显示各帧
                    int repeat = replayIndefinitely?0:1;
                    pseudoVideoGenerator.setRepeat(repeat);
                    //设置输出位置,以当前时间为文件名
                    pseudoVideoGenerator.start(outputLocation+getCurrentTime()+pseudoVideoFormat);
                    //依次将缓冲区内的所有截图按指定间隔加入AnimatedGifEncoder对象
                    for(int i=0;i<size;i++)
                        {
                            bi = (BufferedImage)(getBufferVec().get(i));
                            pseudoVideoGenerator.setDelay(200*replaySpeed);
                             pseudoVideoGenerator.addFrame(bi);
                         }
                    //生成动态的GIF文件
                    pseudoVideoGenerator.finish();
                }
                catch(Exception e)
                {
                     e.printStackTrace();
                }
            }

        generatePseudoVideo方法将缓冲区内的截图集中起来,每副截图作为一帧加入到一个生成器,再对相关参数做必要的设置,最后导出到一个GIF文件中。

        其中,AnimatedGifEncoder类是一段开源程序,用来将一帧或多帧图像转换为一个GIF文件。作者是Kevin Weiner。

         /** * main method of this thread */
        public void run()
            {
                while(true)
                 {
                     try
                         {
                             //将当前屏幕的截图存入缓冲区
                            pushScreenshot();
                            //睡眠一段时间
                            Thread.sleep(new Double(1000*this.snapInterval).longValue());
                            //查看错误标识,一旦有错
                            if(errorFlag)
                                {
                               //立即生成伪视频
                           generatePseudoVideo();
                                //复位错误标识
                                errorFlag = false;
                             }
                        }
                    catch(Exception e)
                     {
                         e.printStackTrace();
                     }
                }
            }

        run()方法是该线程的主要方法,通过轮询方式监测错误标识。如果在自动测试脚本在运行过程中有错误发生,它会将错误标识设为true;run()方法侦测发现该标识后,在第一时间内生成伪视频,再对错误标识进行复位。

        五、总结

        新的日志方案在原有方案的基础上进行了重构,对错误后截图的功能加以萃取和改进,使原有日志系统在不追加任何软硬件投资的前提下,能生成具有类似功能的伪视频。测试人员能够直观地了解自动测试过程,快速定位测试脚本或软件缺陷导致的错误成因,从而高效地优化测试脚本或填写测试报告。

        本例给出的实现使用了GIF格式的动态图片作为生成的伪视频,读者可以按照类似方法,生成诸如SVG,PNG等其它格式的动态图片来再现测试过程。

        对于新日志系统中的各种各样的表现形式:文本日志、截图、以及伪视频,可以使用HTML格式统一展现,有概况有明细,通过超链接将众多日志内容组织在一起,让日志系统能更加友好方便地供测试人员查阅。

你可能感兴趣的:(日志系统)