How to Specify Path of Template for App Engine wit

2020-02-12 09:00发布

I'm using the built-in template package with Go on App Engine.

I have a handler that renders a template to the output.

templates := []string{"templates/head.html", "templates/footer.html"}

func pageIndex(w http.ResponseWriter, r *http.Request) {
  tpls := append([]string{"templates/index.html"}, templates...)
  tpl := template.Must(template.ParseFiles(tpls...))
  err := tpl.ExecuteTemplate(w, "index", map[string]string{
    "Title": "Index Page",
  })

  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}

When I run the local development server this works fine.

When I run the unit test to test the page, it panics and gives me the message:

panic: open templates/index.html: no such file or directory [recovered]

The unit test is as follows:

func TestPageIndex(t *testing.T) {
  inst, _ := aetest.NewInstance(nil)
  //ignoring the errors for brevity
  defer inst.Close()

  req, _ := inst.NewRequest("GET", "/", nil)
  resp := httptest.NewRecorder()
  pageIndex(resp, req)
}

Basically, the problem is that for the unit test, the server is unable to find the path of the template.

How do I specify the path for the template files when running the test?

1条回答
仙女界的扛把子
2楼-- · 2020-02-12 09:30

The problem is that when you run your app e.g. with goapp serve, the current directory is the app root (where app.yaml resides). So normally you provide paths relative to app root.

But when you run tests e.g. with goapp test, the current directory is always the folder containing the test file being run (*_test.go). If the test file is not in the app root (normally it isn't), relative paths that are correctly resolved to the app root will not work when being resolved to another folder (containing the test file).

Here are 2 options for your problem:

1. Change the working directory to the app root

You may use os.Chdir() to change the working directory to your app's root folder prior to calling code that uses relative paths. You may even put this into an init() function, or call it from your test method (whichever suits you).

Let's assume your test file is in the folder: [APP_ROOT]/my/package/some_test.go. You may set the app's root like this (2 levels up in the hierarchy):

if err := os.Chdir("../.."); err != nil {
    panic(err)
}

Note that I would add this line in a package init function in the test file like this:

func init() {
    if err := os.Chdir("../.."); err != nil {
        panic(err)
    }
}

Because if you have multiple test functions in the test file and you run this code multiple times, the result will not be what you want (as we specified to go up 2 levels from the current).

2. Refactoring code

If you want to test code that uses relative paths, you may change / refactor the code to take the base of relative path e.g. from a variable which the test may change (knowing the current directory is its containing folder) so that the original relative path will also work when running from test and being resolved to a different base path.

For example this base path may be the empty string "" when your app is running normally (so it will mean the current folder which in this case is the app root), and when tests are running, you may set it to the app's root (absolute path) or something like "../.." to step 2 levels up in the directory hierarchy (because current directory is the containing folder of the test file).

You can also make the base path to which relative paths are resolved against more configurable, see this question for details: how to reference a relative file from code and tests

查看更多
登录 后发表回答