102_testing.zig 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // A big advantage of Zig is the integration of its own test system.
  3. // This allows the philosophy of Test Driven Development (TDD) to be
  4. // implemented perfectly. Zig even goes one step further than other
  5. // languages, the tests can be included directly in the source file.
  6. //
  7. // This has several advantages. On the one hand it is much clearer to
  8. // have everything in one file, both the source code and the associated
  9. // test code. On the other hand, it is much easier for third parties
  10. // to understand what exactly a function is supposed to do if they can
  11. // simply look at the test inside the source and compare both.
  12. //
  13. // Especially if you want to understand how e.g. the standard library
  14. // of Zig works, this approach is very helpful. Furthermore it is very
  15. // practical, if you want to report a bug to the Zig community, to
  16. // illustrate it with a small example including a test.
  17. //
  18. // Therefore, in this exercise we will deal with the basics of testing
  19. // in Zig. Basically, tests work as follows: you pass certain parameters
  20. // to a function, for which you get a return - the result. This is then
  21. // compared with the EXPECTED value. If both values match, the test is
  22. // passed, otherwise an error message is displayed.
  23. //
  24. // testing.expect(foo(param1, param2) == expected);
  25. //
  26. // Also other comparisons are possible, deviations or also errors can
  27. // be provoked, which must lead to an appropriate behavior of the
  28. // function, so that the test is passed.
  29. //
  30. // Tests can be run via Zig build system or applied directly to
  31. // individual modules using "zig test xyz.zig".
  32. //
  33. // Both can be used script-driven to execute tests automatically, e.g.
  34. // after checking into a Git repository. Something we also make extensive
  35. // use of here at Ziglings.
  36. //
  37. const std = @import("std");
  38. const testing = std.testing;
  39. // This is a simple function
  40. // that builds a sum from the
  41. // passed parameters and returns.
  42. fn add(a: f16, b: f16) f16 {
  43. return a + b;
  44. }
  45. // The associated test.
  46. // It always starts with the keyword "test",
  47. // followed by a description of the tasks
  48. // of the test. This is followed by the
  49. // test cases in curly brackets.
  50. test "add" {
  51. // The first test checks if the sum
  52. // of '41' and '1' gives '42', which
  53. // is correct.
  54. try testing.expect(add(41, 1) == 42);
  55. // Another way to perform this test
  56. // is as follows:
  57. try testing.expectEqual(add(41, 1), 42);
  58. // This time a test with the addition
  59. // of a negative number:
  60. try testing.expect(add(5, -4) == 1);
  61. // And a floating point operation:
  62. try testing.expect(add(1.5, 1.5) == 3);
  63. }
  64. // Another simple function
  65. // that returns the result
  66. // of subtracting the two
  67. // parameters.
  68. fn sub(a: f16, b: f16) f16 {
  69. return a - b;
  70. }
  71. // The corresponding test
  72. // is not much different
  73. // from the previous one.
  74. // Except that it contains
  75. // an error that you need
  76. // to correct.
  77. test "sub" {
  78. try testing.expect(sub(10, 5) == 6);
  79. try testing.expect(sub(3, 1.5) == 1.5);
  80. }
  81. // This function divides the
  82. // numerator by the denominator.
  83. // Here it is important that the
  84. // denominator must not be zero.
  85. // This is checked and if it
  86. // occurs an error is returned.
  87. fn divide(a: f16, b: f16) !f16 {
  88. if (b == 0) return error.DivisionByZero;
  89. return a / b;
  90. }
  91. test "divide" {
  92. try testing.expect(divide(2, 2) catch unreachable == 1);
  93. try testing.expect(divide(-1, -1) catch unreachable == 1);
  94. try testing.expect(divide(10, 2) catch unreachable == 5);
  95. try testing.expect(divide(1, 3) catch unreachable == 0.3333333333333333);
  96. // Now we test if the function returns an error
  97. // if we pass a zero as denominator.
  98. // But which error needs to be tested?
  99. try testing.expectError(error.???, divide(15, 0));
  100. }