github.com/goplus/yap@v0.8.1/ytest/README.md (about)

     1  yaptest - Go+ HTTP Test Framework
     2  =====
     3  [![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop)
     4  [![GitHub release](https://img.shields.io/github/v/tag/goplus/gop.svg?label=Go%2b+release)](https://github.com/goplus/gop/releases)
     5  [![Discord](https://img.shields.io/badge/Discord-online-success.svg?logo=discord&logoColor=white)](https://discord.gg/mYjWCJDcAr)
     6  [![GoDoc](https://pkg.go.dev/badge/github.com/goplus/yap/ytest.svg)](https://pkg.go.dev/github.com/goplus/yap/ytest)
     7  
     8  yaptest is a web server testing framework. This classfile has the file suffix `_ytest.gox`.
     9  
    10  Before using `yaptest`, you need to add `github.com/goplus/yap` to `go.mod`:
    11  
    12  ```
    13  gop get github.com/goplus/yap@latest
    14  ```
    15  
    16  Suppose we have a web server ([foo/get_p_#id.yap](demo/foo/get_p_%23id.yap)):
    17  
    18  ```go
    19  json {
    20  	"id": ${id},
    21  }
    22  ```
    23  
    24  Then we create a yaptest file ([foo/foo_ytest.gox](demo/foo/foo_ytest.gox)):
    25  
    26  ```go
    27  mock "foo.com", new(AppV2)  // name of any YAP v2 web server is `AppV2`
    28  
    29  id := "123"
    30  get "http://foo.com/p/${id}"
    31  ret 200
    32  json {
    33  	"id": id,
    34  }
    35  ```
    36  
    37  The directive `mock` creates the web server by [mockhttp](https://pkg.go.dev/github.com/qiniu/x/mockhttp). Then we write test code directly.
    38  
    39  You can change the directive `mock` to `testServer` (see [foo/bar_ytest.gox](demo/foo/bar_ytest.gox)), and keep everything else unchanged:
    40  
    41  ```go
    42  testServer "foo.com", new(AppV2)
    43  
    44  id := "123"
    45  get "http://foo.com/p/${id}"
    46  ret 200
    47  json {
    48  	"id": id,
    49  }
    50  ```
    51  
    52  The directive `testServer` creates the web server by [net/http/httptest](https://pkg.go.dev/net/http/httptest#NewServer) and obtained a random port as the service address. Then it calls the directive [host](https://pkg.go.dev/github.com/goplus/yap/ytest#App.Host) to map the random service address to `foo.com`. This makes all other code no need to changed.
    53  
    54  
    55  ## match
    56  
    57  This is almost the core concept in `yaptest`. It matches two objects.
    58  
    59  Let’s look at [a simple example](demo/match/simple/simple_yapt.gox) first:
    60  
    61  ```go
    62  id := Var(int)
    63  match id, 1+2
    64  echo id
    65  ```
    66  
    67  Here we define a variable called `id` and match it with expression `1+2`. If the variable is unbound, it is assigned the value of the expression. In this way the value of `id` becomes `3`.
    68  
    69  So far, you've seen `match` like the assignment side. But you cannot assign a different value to a variable that has been bound:
    70  
    71  ```go
    72  id := Var(int)
    73  match id, 1+2
    74  match id, 3
    75  echo id
    76  
    77  match id, 5  // unmatched value - expected: 3, got: 5
    78  ```
    79  
    80  In the second `match` statement, the variable `id` has been bound. At this time, it will be compared with the expression value. If it is equal, it will succeed, otherwise an error will be reported (such as the third `match` statement above).
    81  
    82  The `match` statement [can be complex](demo/match/complex/complex_yapt.gox), such as:
    83  
    84  ```go
    85  d := Var(string)
    86  
    87  match {
    88      "c": {"d": d},
    89  }, {
    90      "a": 1,
    91      "b": 3.14,
    92      "c": {"d": "hello", "e": "world"},
    93      "f": 1,
    94  }
    95  
    96  echo d
    97  match d, "hello"
    98  ```
    99  
   100  Generally, the syntax of the match command is:
   101  
   102  ```go
   103  match <ExpectedObject> <SourceObject>
   104  ```
   105  
   106  Unbound variables are allowed in `<ExpectedObject>`, but cannot appear in `<SourceObject>`. `<ExpectedObject>` and `<SourceObject>` do not have to be exactly the same, but what appears in `<ExpectedObject>` must also appear in `<SourceObject>`. That is, it is required to be a subset relationship (`<ExpectedObject>` is a subset of `<SourceObject>`).
   107  
   108  If a variable in `<ExpectedObject>` has not been bound, it will be bound according to the value of the corresponding `<SourceObject>`; if the variable has been bound, the values on both sides must match.
   109  
   110  The cornerstone of `yaptest` is matching grammar. Let's look at [the example](demo/match/hello/hello_yapt.gox) you saw at the beginning:
   111  
   112  ```go
   113  id := "123"
   114  get "http://foo.com/p/${id}"
   115  
   116  ret 200
   117  json {
   118  	"id": id,
   119  }
   120  ```
   121  
   122  It is [equivalent to](demo/match/diveinto/hello_yapt.gox):
   123  
   124  ```go
   125  id := "123"
   126  get "http://foo.com/p/${id}"
   127  
   128  send                 // send request
   129  match 200, resp.code // assert resp.code == 200
   130  match "application/json", resp.header.get("Content-Type")
   131  match {              // assert resp.body.id == id
   132  	"id": id,
   133  }, resp.body
   134  ```