Spustit jako prezentaci

Testování

Doporučené postupy v programování - cvičení

MFF UK

Unit testy

Testování na úrovni nejmenší ucelené jednotky v daném jazyce

Třídy by se měly testovat v co největší izolaci.

V praxi:

Unit testy

Co tím můžeme získat?

Unit testy

Mají být:

Unit testy

Zdroj příkladů


Google Testing Blog
http://GoogleTesting.blogspot.com/

Tip na knížku

Kent Beck: Programování řízené testy

Počet testů

Příklad: počet testů

Kolik testů byste napsali na otestování této funkce?

public void decide(int a, int b, int c, int d, int e, int f) {
  if (a > b || c > d || e > f) {
    DoOneThing();
  } else {
    DoAnother();
  }
}

Příklad: počet testů

Kolik testů byste napsali na otestování této funkce?

public void decide(int a, int b, int c, int d, int e, int f) {
  if (tallerThan(a, b) || harderThan(c, d) || heavierThan(e, f)) {
    DoOneThing();
  } else {
    DoAnother();
  }
}

boolean tallerThan(int a, int b) { return a > b; }
boolean harderThan(int c, int d) { return c > d; }
boolean heavierThan(int e, int f) { return e > f; }

Příklad: počet testů

Kolik testů byste napsali na otestování této funkce?

public void decide(int a, int b, int c, int d, int e, int f) {
  if (tallerThan(a, b) || harderThan(c, d) || heavierThan(e, f)) {
    DoOneThing();
  } else {
    DoAnother();
  }
}

boolean tallerThan(int a, int b) { return a > b; }
boolean harderThan(int c, int d) { return c > d; }
boolean heavierThan(int e, int f) { return e > f; }

The word "correct" is quoted, because the result is not objective truth, but subjective opinion.

Testovatelnost

Příklad: testovatelnost funkce (Python)

def GetTestResults(self):
  # Check if results have been cached.
  results = cache.get('test_results', None)
  if results is None:
    # No results in the cache, so check the database.
    results = db.FetchResults(SQL_SELECT_TEST_RESULTS)
  # Count passing and failing tests.
  num_passing = len([r for r in results if r['outcome'] == 'pass'])
  num_failing = len(results) - num_passing
  return num_passing, num_failing

Příklad: testovatelnost funkce (Python)

def GetTestResults(self):
  # Check if results have been cached.
  results = cache.get('test_results', None)
  if results is None:
    # No results in the cache, so check the database.
    results = db.FetchResults(SQL_SELECT_TEST_RESULTS)
  # Count passing and failing tests.
  num_passing = len([r for r in results if r['outcome'] == 'pass'])
  num_failing = len(results) - num_passing
  return num_passing, num_failing

Příklad: testovatelnost funkce (Python)

def GetTestResults(self):
  results = self._GetTestResultsFromCache()
  if results is None:
    results = self._GetTestResultsFromDatabase()
  return self._CountPassFail(results)


def _GetTestResultsFromCache(self):
  return cache.get('test_results', None)

def _GetTestResultsFromDatabase(self):
  return db.FetchResults(SQL_SELECT_TEST_RESULTS)

def _CountPassFail(self, results):
  num_passing = len([r for r in results if r['outcome'] == 'pass'])
  num_failing = len(results) - num_passing
  return num_passing, num_failing

Příklad: join

Příklad: výpis polí (Java)

Napište unit testy

public class ArrayUtils {
    /* ... */

    /* join(["ab", "cd"], ", ", "'", "'") -> "'ab', 'cd'" */
    public String join(Iterable<?> data, String sep,
        String prefix, String suffix);

}

Příklad: výpis polí (Java)

Napište unit testy

public class ArrayUtils {
    /* ... */

    /* join(["ab", "cd"], ", ", "'", "'") -> "'ab', 'cd'" */
    public String join(Iterable<?> data, String sep,
        String prefix, String suffix);

}

Chybí podrobnější dokumentace?

Napište testy podle toho, jaké chování byste očekávali!

Zdrojové soubory si můžete stáhnout na této adrese: d3s.mff.cuni.cz/teaching/programming_practices/labs/ArrayUtils.zip

Příklad: Rectangle

Příklad: reprezentace obdelníku (C++)

Napište unit testy

class Rectangle {
    public:

    Rectangle( double l, double t, double r, double b );
    Rectangle( Point p1, Point p2, Point p3, Point p4 );

    double computeArea();

    void rotate( double radians );
    void move( double x, double y );

    vector<Point> getPoints();
}

Zdrojové soubory si můžete stáhnout na této adrese: d3s.mff.cuni.cz/teaching/programming_practices/labs/Rectangle.zip

Příklad: největší společný dělitel

Příklad: největší společný dělitel (C)

Napište unit testy

long gcd(long a, long b) {
    /* ... */
}

Here we write tests for white-box. It should be discussed how the tests differ and when it is better/worse.

Will the students find a bug?

Příklad: největší společný dělitel (C)

Napište unit testy

long gcd(long a, long b) {
    if (b==0) 
        return a;
    else
        return gcd(a, a % b);
}

Zdroják si můžete okopírovat zde: d3s.mff.cuni.cz/teaching/programming_practices/labs/gcd.java

Příklad: properties

Příklad: properties

Otestujte třídu

/* Stores <key, value> pairs. */
public class Properties {
    public void set(String key, String value);
    /* Returns null for unknown key. */
    public String get(String key);
    /* Save to file as
     * key = value
     * pairs on separate lines.
     */
    public void save(String filename);
    /* Load from a file. */
    public void load(String filename);
}

Zdrojové soubory si můžete stáhnout na této adrese: d3s.mff.cuni.cz/teaching/programming_practices/labs/Properties.zip

Příklad: properties

Popis není dostatečný?

Dodefinujte si chování v testech.

Příklad: properties

Objevily testy nějaké chyby?

Příklad: properties

Objevily testy nějaké chyby?

  • There is missing a specification of exceptions.
  • If only load and save were given Writer instead of file name (or some stream), it would be possible to "mock" it by a string writer and test everything in memory, which is definitely more convenient.

Příklad: sprintf

Příklad: sprintf (PHP)

Napište unit testy pro %d

/* Return a formatted string. */
string sprintf(string $format [, mixed $args [, mixed $... ]])

Direktivu tvoří:

  1. %
  2. znaménko (volitelné)
  3. vycpávka [padding] (volitelné)
  4. zarovnání (volitelné)
  5. minimální šířka (volitelné)
  6. přesnost (volitelné)
  7. specifikace typu (volitelné)

Testy vložte do třídy TestSprintf jako její metody.

The task should contain this complete description:

string sprintf ( string $format [, mixed $args [, mixed $... ]] )

The format string is composed of zero or more directives:
ordinary characters (excluding %) that are copied directly
to the result, and conversion specifications, each of which
results in fetching its own parameter.
This applies to both sprintf() and printf().

Each conversion specification consists of a percent sign (%),
followed by one or more of these elements, in order:

1. An optional sign specifier that forces a sign (- or +) to
   be used on a number. By default, only the - sign is used on
   a number if it's negative. This specifier forces positive
   numbers to have the + sign attached as well, and was added
   in PHP 4.3.0.
2. An optional padding specifier that says what character will
   be used for padding the results to the right string size.
   This may be a space character or a 0 (zero character).
   The default is to pad with spaces. An alternate padding
   character can be specified by prefixing it with a single
   quote ('). See the examples below.
3. An optional alignment specifier that says if the result should
   be left-justified or right-justified. The default is
   right-justified; a - character here will make it left-justified.
4. An optional number, a width specifier that says how many characters
   (minimum) this conversion should result in.
5. An optional precision specifier in the form of a period (`.')
   followed by an optional decimal digit string that says how many
   decimal digits should be displayed for floating-point numbers.
   When using this specifier on a string, it acts as a cutoff point,
   setting a maximum character limit to the string.

A type specifier that says what type the argument data should be
treated as. Possible types:
    % - a literal percent character. No argument is required.
    b - the argument is treated as an integer, and presented as
        a binary number.
    c - the argument is treated as an integer, and presented as
        the character with that ASCII value.
    d - the argument is treated as an integer, and presented as
        a (signed) decimal number.
    e - the argument is treated as scientific notation (e.g. 1.2e+2).
        The precision specifier stands for the number of digits
        after the decimal point since PHP 5.2.1. In earlier
        versions, it was taken as number of significant digits
        (one less).
    E - like %e but uses uppercase letter (e.g. 1.2E+2).
    u - the argument is treated as an integer, and presented as
        an unsigned decimal number.
    f - the argument is treated as a float, and presented as
        a floating-point number (locale aware).
    F - the argument is treated as a float, and presented
        as a floating-point number (non-locale aware).
        Available since PHP 4.3.10 and PHP 5.0.3.
    g - shorter of %e and %f.
    G - shorter of %E and %f.
    o - the argument is treated as an integer, and presented
        as an octal number.
    s - the argument is treated as and presented as a string.
    x - the argument is treated as an integer and presented as
        a hexadecimal number (with lowercase letters).
    X - the argument is treated as an integer and presented as
        a hexadecimal number (with uppercase letters).

The format string supports argument numbering/swapping. Here is an example:

$num = 5;
$location = 'tree';

$format = 'The %2$s contains %1$d monkeys';
printf($format, $num, $location);


...

The End

Tohle je poslední cvičení

Pokud máte připomínky či náměty, napište nám.

Klidně až po zapsání známky ;-).