Come scrivere test per codice che sta guidando Robot e altre funzionalità esterne?

0

Ho del codice che uso per fare regolarmente screenshot del mio schermo - è utile calcolare quanto di un dato giorno trascorro su varie attività. Assomiglia a questo:

/**
 * Code modified from code given in
 * http://whileonefork.blogspot.co.uk/2011/02/java-multi-monitor-screenshots.html following a SE
 * question at
 * http://stackoverflow.com/questions/10042086/screen-capture-in-java-not-capturing-whole-screen and
 * then modified by a code review at
 * http://codereview.stackexchange.com/questions/10783/java-screengrab
 */
package com.tmc.personal;

import java.awt.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

// TODO: improve screencapture tool by having it not take a photo when the mouse hasn't moved...

class ScreenCapture implements Runnable {

  private int minsBetweenScreenshots = 5;
  private String workingDirectory = "";

  public ScreenCapture(String string, int i) {
    workingDirectory = string;
    minsBetweenScreenshots = i;
  }


  private void tryWritingScreenshotToFile(int indexOfPicture) {
    try {
      Image scaledImg = takeScreenshot();
      storeImageToFile(workingDirectory + "ScreenCapture" + indexOfPicture, scaledImg);
    } catch (IOException e1) {
      // skip, move to the next one
    } catch (AWTException e) {
      // photo didn't work skip and move on.
    }
  }


  private Image takeScreenshot() throws AWTException {
    Rectangle allScreenBounds = getAllScreenBounds();
    Robot robot = new Robot();
    BufferedImage img = robot.createScreenCapture(allScreenBounds);
    return scaleImage(img);
  }

  private void storeImageToFile(String filename, Image scaledImg) throws IOException {
    ImageIO.write(toBufferedImage(scaledImg), "jpg",
        new File(filename + ActivityLogger.getDateTime() + ".jpg"));
  }

  // code from
  // http://www.java-forums.org/new-java/2790-how-save-image-jpg.html
  private BufferedImage toBufferedImage(Image src) {
    int w = src.getWidth(null);
    int h = src.getHeight(null);
    int type = BufferedImage.TYPE_INT_RGB; // other options
    BufferedImage dest = new BufferedImage(w, h, type);
    Graphics2D g2 = dest.createGraphics();
    g2.drawImage(src, 0, 0, null);
    g2.dispose();
    return dest;
  }

  private Image scaleImage(BufferedImage img) {
    int scaledWidth = (int) (img.getWidth() * 0.5);
    int scaledHeight = (int) (img.getHeight() * 0.5);
    Image scaledImg =
        img.getScaledInstance(scaledWidth, scaledHeight, BufferedImage.SCALE_AREA_AVERAGING);
    return scaledImg;
  }

  /**
   * Okay so all we have to do here is find the screen with the lowest x, the screen with the lowest
   * y, the screen with the higtest value of X+ width and the screen with the highest value of
   * Y+height
   * 
   * @return A rectangle that covers the all screens that might be nearby...
   */
  private Rectangle getAllScreenBounds() {
    Rectangle allScreenBounds = new Rectangle();
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] screens = ge.getScreenDevices();

    int farx = 0;
    int fary = 0;
    for (GraphicsDevice screen : screens) {
      Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
      // finding the one corner
      if (allScreenBounds.x > screenBounds.x) {
        allScreenBounds.x = screenBounds.x;
      }
      if (allScreenBounds.y > screenBounds.y) {
        allScreenBounds.y = screenBounds.y;
      }
      // finding the other corner
      if (farx < (screenBounds.x + screenBounds.width)) {
        farx = screenBounds.x + screenBounds.width;
      }
      if (fary < (screenBounds.y + screenBounds.height)) {
        fary = screenBounds.y + screenBounds.height;
      }
      allScreenBounds.width = farx - allScreenBounds.x;
      allScreenBounds.height = fary - allScreenBounds.y;
    }
    return allScreenBounds;
  }

  @Override
  public void run() {
    int indexOfPicture = 1000;
    while (true) {
      tryWritingScreenshotToFile(indexOfPicture++);
      ActivityLogger.waitForNextSampleTime(minsBetweenScreenshots);
    }
  }

}

Il comportamento previsto della classe è che richiede uno screenshot a schermo intero (inclusi monitor esterni) ogni cinque minuti ...

Mi sono recentemente innamorato di Test Driven Development su altri progetti e sono tornato a questo vecchio codice. Ma essendo onesto, non ho idea di dove iniziare con i test di scrittura per questo - tutto è così strettamente connesso al mondo esterno che semplici prove non sono possibili - è l'approccio migliore in queste situazioni?

    
posta Joe 27.03.2014 - 17:41
fonte

1 risposta

4

In senso stretto, non puoi . Potresti prendere in giro le API, ma dovresti solo provare che le stai definendo in un certo modo nell'implementazione. Ciò non dimostra che l'implementazione sia corretta: se fai ipotesi errate nell'implementazione, duplichi quegli errori nei test. Inoltre, i test saranno fragili, perché stai testando i dettagli di implementazione. Quando l'implementazione cambia, anche i test dovranno cambiare.

Potresti adottare il puro approccio di programmazione funzionale e creare una nuova API che emetta IO comandi da eseguire (invece di eseguire effettivamente i comandi). Ad esempio, potresti scrivere funzioni che restituiscono ScreenCapture oggetti che contengono i dettagli di ciò che stai cercando di fare, ad es il rettangolo dello schermo che desideri acquisire. Questi sono solo oggetti dati - in realtà non fanno nulla. Ma potresti testare che gli oggetti comando corretti vengono restituiti con determinati argomenti ...

... Tuttavia, ad un certo punto alcuni codici devono tradurre quegli oggetti comando in effettive chiamate API Robot. Come dimostrate che quel codice è corretto? Sei tornato al punto di partenza. Alla fine della giornata, ti servirà una prova da qualche parte . Le revisioni tra pari ti aiuteranno ad esporre i dettagli che potresti aver perso.

I test possono esporre la presenza di bug, ma mai la loro assenza.

    
risposta data 27.03.2014 - 18:04
fonte

Leggi altre domande sui tag