Say i have a data structure like this:
type Foo struct {
Bar []struct {
FooBar string
}
}
And i fill it such that Bar has 3 elements. Now, using the template library, how can i access say the 3rd element's FooBar in that slice? I have tried the following with no success:
{Foo.Bar[2].FooBar}
{Foo.Bar.2.FooBar}
Now, i know that i can use {.repeated section Foo.Bar} {FooBar} {.end}, but that gives me the value of foobar for each element, rather than just a specific one. I have googled and asked on irc to no avail...
Using the new text/template or html/template:
package main
import (
"fmt"
"text/template" // or html/template
"os"
)
func main() {
tmpl, err := template.New("name").Parse("{{index . 0}}")
if err != nil {
fmt.Println(err)
return
}
tmpl.Execute(os.Stdout, []string{"yup, that's me", "not that!"})
}
I'm fairly certain this just isn't possible. Perhaps there's a way you could restructure your data so that it's all named fields.
Or just write some more logic in your actual application. Array indexing is somewhat beyond the scope of the template package I would think.
Related
Let's say I have a package with the following code:
package paths
type FilePath struct {
PathA string
}
func (c FilePath) GetPathA() string {
if err := PathExists(PathA); err != nil {
return ""
}
return PathA + "foo"
}
func PathExists(p string) error {
// call os and file methods
return err
}
How do I mock out the PathExists dependency to test FilePath? Also, method PathExists is being used by a lot of other packages as well. (I am open to suggestions of refactoring this to make it test friendly, keeping the following pointers in mind)
I have come across a few different approaches but none of them seems intuitive or idiomatic to me.
Have a global variable PE := PathExists in the package; in GetPathA, call err := PE(PathA) and in the test overwrite PE with a mock method.
Issue: If test package is something like paths_test, I will have to export PE which allows clients of the package to overwrite it as well.
Make PathExists a field of FilePath and mock the field in test.
Issue: Clients when using the package, will have to initialize PathExists field, or I provide a constructor of the form NewFilePath(PathtA string) which initializes the fields for me. In the actual use case there are a lot of fields, hence this approach fails as well.
Use an interface and embed it within the struct. When client uses it initialize with the actual method and for test mock it.
type PathExistser interface{
PathExists(p string) error
}
type FilePath struct{
PathA string
PathExister
}
type Actual struct{}
func (a Actual) PathExists(p string) error {
return PathExists(p)
}
Issue: Client again needs to provide the right implementation of the interface.
I have learnt of few more approaches doing something simimlar to the above options, such as make the method PathExists an argument for GetPathA, etc. All have the same concerns. Basically, I don't want the users of this package to have to figure out what should be the right input parameter to make sure the struct works as expected. Neither do I want the users to overwrite the behaviour PathExists.
This seems like a very straightforward problem and I seem to be missing something very funamental about go testing or mocking. Any help would be appreciated, thanks.
Method names are just for example. In reality GetPathA or PathExists would be way more complex.
To address the issue from your 1. approach, you can use an internal package which you'll then be able to import in paths_test but clients of your package won't be.
package paths
import (
// ...
"<your_module_path>/internal/osutil"
)
func PathExists(p string) error {
return osutil.PathExists(p)
}
package osutil
var PathExists = func(p string) error {
// call os and file methods
return err
}
// Use a mutex to make sure that if you have
// multiple tests using mockPathExists and running
// in parallel you avoid the possiblity of a data race.
//
// NOTE that the mutex is only useful if *all* of your tests
// use MockPathExists. If only some do while others don't but
// still directly or indirectly cause the paths.PathExists
// function to be invoked then you still can run into a data
// race problem.
var mu sync.Mutex
func MockPathExists(mock func(p string) error) (unmock func()) {
mu.Lock()
original := PathExists
PathExists = mock
return func() {
PathExists = original
mu.Unlock()
}
}
package paths_test
import (
// ...
"<your_module_path>/internal/osutil"
)
func TestPathExists(t *testing.T) {
unmock := osutil.MockPathExists(myPathExistsMockImpl)
defer unmock()
// do your test
}
I have a piece of code which accepts an io.Writer implementation as an argument.
func printSummary(writer io.Writer) {
// Implementation of the 'printSummary' method goes here.
}
Now, I can easily create a mock to create a unit test.
This would look like the following:
type ioWriterMock struct {
writtenBytes []byte
}
func (writer *ioWriterMock) Write(p []byte) (int, error) {
writer.writtenBytes = append(writer.writtenBytes, p...)
return 0, nil
}
However, this does mean that I need to declare my mock outside of my unit test, which makes it available in the whole package.
I would like to create my test, and that everything that my test depends on is inside the test.
This for the simple reason that everything is in one place and that I don't need to scan different files in my package to find the different parts that are required for my test.
In a unit test, you can create a struct and define functions.
This is done using the following approach:
func TestParse(t *testing.T) {
type utCase struct {
name string
summary string
expectedWrittenBytes []byte
}
createUtCase := func(name, summary string, expWrittenBytes []byte) utCase {
retVal := new(utCase)
retVal.name = name
retVal.summary = summary
retVal.expectedWrittenBytes = expWrittenBytes
return *retVal
}
}
So embedding the io.Writer mock in the unit test can be done in the following way:
func TestParse(t *testing.T) {
type ioWriterMock struct {
writtenBytes []byte
}
}
One thing which I don't find is how I'm able to implement the io.Writer interface on that type.
As suggested by #mkopriva, put the ioWriterMock definition next to the TestParse function in the _test.go file. In go, it is not allowed to put the definition of a function inside another function. You can only define the struct type in a function.
By defining the ioWriterMock type and Write method inside the test file, it will only be visible during test execution. It won't be present and thus visible when using the package outside of a test.
Also, considering the given example, a bytes.Buffer would be a good free substitute to your ioWriterMock as suggested by #Flimzy.
It is important to me to be able to assert how many times a fake / mocked method is called in my tests and I'm wondering what is the best way to do this without using something like testify. In my case, the call to the mocked method is the result of some recursive call.
Lets say I have table driven tests with various animals, I want to assert that Hello is actually called for some tests but not for others. In some cases, it should be called more than once for given test (iterating over a slice).
Is it appropriate to just add a counter and make an assertion on that in my table driven test? It seems to me like maybe there is a better way to do this.
If I do add a counter to the hello method... where is it appropriate to deal with and check this. In the fake method itself or in the test etc?
type fakeFarmService struct {
abc.someFarmServiceInterface
}
func (f *fakeFarmService) Hello(ctx context.Context, in *abc.FarmRequest) (*abc.FarmResponse, error) {
if in.GetAnimal() == Monkey {
return &abc.HelloResponse{}, nil
}
return nil, errors.New("an error")
}
I've used the approach of counter on the struct and then asserting it inside the package level unit test multiple times in the past. Still, it's probably only until the level of package, when you would like to test such an internal assertions. I believe it's an accepted way of doing this in Go. Just be careful about properly synchronizing the access to the counter, if you decide to use a global variable or run the tests concurrently.
package main
import (
"fmt"
"sync"
"testing"
)
type fakeable interface {
Hello()
}
type fakeFarmService struct {
mu sync.Mutex
counter int
}
func (f *fakeFarmService) Hello() {
f.mu.Lock()
f.counter++
f.mu.Unlock()
}
func helloCaller(callee fakeable) {
callee.Hello()
}
func TestCallingTheHello(t *testing.T) {
fakeSvc := &fakeFarmService{}
helloCaller(fakeSvc)
helloCaller(fakeSvc)
// we expect that Hello method of fakeable was called 2 times
fakeSvc.mu.Lock()
defer fakeSvc.mu.Unlock()
if c := fakeSvc.counter; c != 2 {
t.Errorf("unexpected call count, want 2, got %d", c)
}
}
func main() {
TestCallingTheHello(&testing.T{})
}
https://play.golang.org/p/RXKuLKIZwc (test error won't work inside the playground)
Some good material on advanced testing in Go
Testing Techniques by Andrew Gerrand
NewStore TechTalk - Advanced Testing with Go by Mitchell Hashimoto
Is there a simple way like template.ParseFiles("base.html", "home.html") but for strings to build a template from a set of strings?
I have a base template and a list of pages templates (all as strings) that I want to build on top of base template.
I figured out how to merge them, but I my solution is quite verbose and doesn't look elegant enough, even though working.
You may create a new, empty template using template.New() function. Then you may use the Template.New() method to create a new, empty, associated template. And you may parse "into" this using the Template.Parse() method.
Here's how it could look like:
func parseTemplates(templs ...string) (t *template.Template, err error) {
t = template.New("_all")
for i, templ := range templs {
if _, err = t.New(fmt.Sprint("_", i)).Parse(templ); err != nil {
return
}
}
return
}
Testing it:
t, err := parseTemplates(
`{{define "one"}}I'm #1.{{end}}`,
`{{define "two"}}I'm #2, including #1: {{template "one" .}}{{end}}`,
)
if err != nil {
panic(err)
}
if err = t.ExecuteTemplate(os.Stdout, "two", nil); err != nil {
panic(err)
}
Output (try it on the Go Playground):
I'm #2, including #1: I'm #1.
Also see related question: Go template name
Note
While we could call the Template.Parse() method on a single template multiple times, and it would parse multiple named templates properly, it is still advisable to acquire a new template.Template for each by calling Template.New(). Because if the template texts have content outside of named templates, they will be overwritten and only the last would be retained. For example: abc {{define "one"}}no 1{{end}}. The static text "abc" would be lost by a subsequent Template.Parse() call.
This is also noted in the doc of Template.Parse():
(In multiple calls to Parse with the same receiver template, only one call can contain text other than space, comments, and template definitions.)
Maybe
for _, templ := range ListOfPagesTemplates{
YourBaseTemplate.Parse(templ)
}
err check absent for simplicity of reading
Is it possible to access the name of current template in Golang text/html/template without passing it as a data element to the template?
Thanks!
I'm hoping this is what you meant (from http://golang.org/pkg/text/template/#Template.Name)
func (t *Template) Name() string
"Name returns the name of the template."
If you mean to access the template name from within the template, I can only think to either add a function to the template.FuncMap, or, as you suggested to add the name as a data element.
The first would probably look something like:
var t = template.Must(template.New("page.html").ParseFiles("page.html"))
t.Funcs(template.FuncMap{"name": fmt.Sprint(t.Name())})
but I can't get it to work in the quick time I've messed about with it. Hopefully it might help point you in the right direction.
It would probably be easier in the long run just to add the name as a data element.
EDIT: In case anyone wants to know how to do it using template.FuncMap, it's basically a matter of defining the function after you create the template, then adding it to the FuncMap:
Full running example:
func main() {
const text = "{{.Thingtype}} {{templname}}\n"
type Thing struct {
Thingtype string
}
var thinglist = []*Thing{
&Thing{"Old"},
&Thing{"New"},
&Thing{"Red"},
&Thing{"Blue"},
}
t := template.New("things")
templateName := func() string { return t.Name() }
template.Must(t.Funcs(template.FuncMap{"templname": templateName}).Parse(text))
for _, p := range thinglist {
err := t.Execute(os.Stdout, p)
if err != nil {
fmt.Println("executing template:", err)
}
}
}
Outputs:
Old things
New things
Red things
Blue things
Playground link: http://play.golang.org/p/VAg5Gv5hCg