Git Product home page Git Product logo

learn-go-with-tests's Introduction

Learn Go with Tests

Art by Denise

Go Report Card

Formats

Translations

Support me

I am proud to offer this resource for free, but if you wish to give some appreciation:

Why

Table of contents

Go fundamentals

  1. Install Go - Set up environment for productivity.
  2. Hello, world - Declaring variables, constants, if/else statements, switch, write your first go program and write your first test. Sub-test syntax and closures.
  3. Integers - Further Explore function declaration syntax and learn new ways to improve the documentation of your code.
  4. Iteration - Learn about for and benchmarking.
  5. Arrays and slices - Learn about arrays, slices, len, varargs, range and test coverage.
  6. Structs, methods & interfaces - Learn about struct, methods, interface and table driven tests.
  7. Pointers & errors - Learn about pointers and errors.
  8. Maps - Learn about storing values in the map data structure.
  9. Dependency Injection - Learn about dependency injection, how it relates to using interfaces and a primer on io.
  10. Mocking - Take some existing untested code and use DI with mocking to test it.
  11. Concurrency - Learn how to write concurrent code to make your software faster.
  12. Select - Learn how to synchronise asynchronous processes elegantly.
  13. Reflection - Learn about reflection
  14. Sync - Learn some functionality from the sync package including WaitGroup and Mutex
  15. Context - Use the context package to manage and cancel long-running processes
  16. Intro to property based tests - Practice some TDD with the Roman Numerals kata and get a brief intro to property based tests
  17. Maths - Use the math package to draw an SVG clock
  18. Reading files - Read files and process them
  19. Templating - Use Go's html/template package to render html from data, and also learn about approval testing
  20. Generics - Learn how to write functions that take generic arguments and make your own generic data-structure
  21. Revisiting arrays and slices with generics - Generics are very useful when working with collections. Learn how to write your own Reduce function and tidy up some common patterns.

Build an application

Now that you have hopefully digested the Go Fundamentals section you have a solid grounding of a majority of Go's language features and how to do TDD.

This next section will involve building an application.

Each chapter will iterate on the previous one, expanding the application's functionality as our product owner dictates.

New concepts will be introduced to help facilitate writing great code but most of the new material will be learning what can be accomplished from Go's standard library.

By the end of this, you should have a strong grasp as to how to iteratively write an application in Go, backed by tests.

  • HTTP server - We will create an application which listens to HTTP requests and responds to them.
  • JSON, routing and embedding - We will make our endpoints return JSON and explore how to do routing.
  • IO and sorting - We will persist and read our data from disk and we'll cover sorting data.
  • Command line & project structure - Support multiple applications from one code base and read input from command line.
  • Time - using the time package to schedule activities.
  • WebSockets - learn how to write and test a server that uses WebSockets.

Testing fundamentals

Covering other subjects around testing.

Questions and answers

I often run in to questions on the internets like

How do I test my amazing function that does x, y and z

If you have such a question raise it as an issue on github and I'll try and find time to write a short chapter to tackle the issue. I feel like content like this is valuable as it is tackling people's real questions around testing.

  • OS exec - An example of how we can reach out to the OS to execute commands to fetch data and keep our business logic testable/
  • Error types - Example of creating your own error types to improve your tests and make your code easier to work with.
  • Context-aware Reader - Learn how to TDD augmenting io.Reader with cancellation. Based on Context-aware io.Reader for Go
  • Revisiting HTTP Handlers - Testing HTTP handlers seems to be the bane of many a developer's existence. This chapter explores the issues around designing handlers correctly.

Meta / Discussion

Contributing

  • This project is work in progress If you would like to contribute, please do get in touch.
  • Read contributing.md for guidelines
  • Any ideas? Create an issue

Background

I have some experience introducing Go to development teams and have tried different approaches as to how to grow a team from some people curious about Go into highly effective writers of Go systems.

What didn't work

Read the book

An approach we tried was to take the blue book and every week discuss the next chapter along with the exercises.

I love this book but it requires a high level of commitment. The book is very detailed in explaining concepts, which is obviously great but it means that the progress is slow and steady - this is not for everyone.

I found that whilst a small number of people would read chapter X and do the exercises, many people didn't.

Solve some problems

Katas are fun but they are usually limited in their scope for learning a language; you're unlikely to use goroutines to solve a kata.

Another problem is when you have varying levels of enthusiasm. Some people just learn way more of the language than others and when demonstrating what they have done end up confusing people with features the others are not familiar with.

This ends up making the learning feel quite unstructured and ad hoc.

What did work

By far the most effective way was by slowly introducing the fundamentals of the language by reading through go by example, exploring them with examples and discussing them as a group. This was a more interactive approach than "read chapter x for homework".

Over time the team gained a solid foundation of the grammar of the language so we could then start to build systems.

This to me seems analogous to practicing scales when trying to learn guitar.

It doesn't matter how artistic you think you are, you are unlikely to write good music without understanding the fundamentals and practicing the mechanics.

What works for me

When I learn a new programming language I usually start by messing around in a REPL but eventually, I need more structure.

What I like to do is explore concepts and then solidify the ideas with tests. Tests verify the code I write is correct and documents the feature I have learned.

Taking my experience of learning with a group and my own personal way I am going to try and create something that hopefully proves useful to other teams. Learning the fundamentals by writing small tests so that you can then take your existing software design skills and ship some great systems.

Who this is for

  • People who are interested in picking up Go.
  • People who already know some Go, but want to explore testing with TDD.

What you'll need

  • A computer!
  • Installed Go
  • A text editor
  • Some experience with programming. Understanding of concepts like if, variables, functions etc.
  • Comfortable using the terminal

Feedback

MIT license

Logo is by egonelbre What a star!

learn-go-with-tests's People

Contributors

ahmgeek avatar aivchen avatar alexandear avatar alexvpopov avatar alrighttheresham avatar ardinusawan avatar awulkan avatar cpustejovsky avatar dario-piotrowicz avatar enkeyz avatar gypsydave5 avatar hackeryarn avatar jossy avatar kandros avatar leighstillard avatar lnryan avatar lotia avatar mukulrawat1986 avatar mxygem avatar nakamasato avatar pamelafox avatar pdbrito avatar pesterhazy avatar pityonline avatar quii avatar ruthmoog avatar rxx avatar sleeping-barber avatar tracypholmes avatar uponthesky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

learn-go-with-tests's Issues

Chapter headings - hard to follow along online

When following along online: after the first couple of chapters, you basically get "Write tests.." or "Refactor" headings. It's very hard to tell where you are on the page or get back to a specific section (especially in the bigger chapters) because it all looks the same. (screenshot included).
image

I think this is due to how GitBook uses Markdown to determine chapters, but would you be open to the idea of changing the Level 3 headings to match more of what's in the content, and let the bulk of Write the test/Refactor/etc.. change to Level 4?

I know it's a lot of work, and I definitely don't mind contributing to help out with that.

Add note about different benchmarking command on Windows

Thanks for this awesome book!
I'm running Windows 10 and it took me a while to figure out that (at least using PowerShell) one has to use go test -bench="." instead of just go test -bench=. to run the benchmarks.
I think it would be cool to include a note for Windows users stating this slight difference (hope I didn't just overlook it). 😇

initializing structs

The chapter of structs does not mention new, to create structs.This is not much of problem, but ...
Then comes the chapter on HTTP server, where you do something like this:

    server := &PlayerServer{}

The unattentive reader just goes by (me reading on the train ...), the aware reader looks at the & and thinks:

mmm ... strange. I know this from C. Why do we deference this here?

Now, I read somewhere along in your AWESOME book (I'm already using some of the techniques in Python) that we don't want to pass values by copying them into the functions, so it makes sense to me. But I am thinking it's worth an explicit explanation on this syntax.

If you accept a PR I don't mind trying to explain it.

Error in `it records wins on POST` test

The test condition len(store.winCalls) != 1 will always return False because of the previous test also recording a win.

The store should ideally be reset for every test to avoid making the tests dependent on each other.

Introduce structs

ideas...

  • Start with a number of functions that take the same collection of primitives
  • Then show how we can refactor these things into a struct
  • Add some methods?
  • Now that the reader knows about structs we could maybe bring in table based tests too

Avoid pointer stuff for now.

The next chapter can do pointers to show how we can modify state

Typing mistake

A typing error in the chapter of mocking-wip
func Countdown(out io.Writer) { for i := 5; i > 0; i-- { fmt.Fprintln(out, i) } fmt.Fprint(w, "Go!") }
fmt.Fprint(w, "Go!") ==>fmt.Fprint(out, "Go!")

Btw,this approach to learn go is awesome,very helpful, look forward your updating.

Context: removing ctx field from SpyStore

In the website's Context section, the text states:

We removed the reference to ctx from the SpyStore's fields because it's no longer interesting to us.

I searched but I couldn't find the section where ctx was added to SpyStore.

Also, the subsequent test still checks this field:

    if store.ctx != request.Context() {
        t.Errorf("store was not passed through a context %v", store.ctx)
    }

These lines seem to have been removed from the code file, but are still present in the markdown file.

Unnecessary test codes in "Concurrency" chapter

I think the checking of num is unnecessary in chapter concurrency.

want := len(websites)
    got := len(actualResults)
    if want != got {
        t.Fatalf("Wanted %v, got %v", want, got)
    }

Because reflect.DeepEqual has done it for ourselves. I think it's good for the codes just like the v0-CheckWebsites_test.go:

want := map[string]bool{
		"http://google.com":          true,
		"http://blog.gypsydave5.com": true,
		"waat://furhurterwe.geds":    false,
	}

got := CheckWebsites(mockWebsiteChecker, websites)

if !reflect.DeepEqual(want, got) {
    t.Fatalf("Wanted %v, got %v", want, got)
}

PDF is missing illustration

Hi,
I don't know if this is by purpose but the PDF is missing the awesome illustration which the ePub got as a Cover.

Also maybe a tag with the version of release would be a nice feature on a page.

Chéers!

Chapter about database/sql testing

I'm not quite sure if that's covered in other chapters, but I'm struggling with testing my database/sql stuff.
The mocking and dependency injection chapters were useful, but I'm still lost.

Let's say, that I've got something like that:

type Connection struct {
	*sql.DB
}

func NewDatabaseConnection(host, database, user, password string) (*Connection, error) {
	u := &url.URL{
		Scheme: "sqlserver",
		User:   url.UserPassword(user, password),
		Host:   fmt.Sprintf("%s:%d", host, 1433),
	}

	db, err := sql.Open("mssql", u.String())
	if err != nil {
		log.Fatal("Error opening database connection:", err)
	}

	return &Connection{db}, nil
}

How, if it's even needed, should I test that? Or something like a GetUser function.
A chapter about that would be awesome =) Maybe, since we've already got a "HTTP server" and "JSON" chapter, a little extension to those?

File System

Chapter with examples of how to test code that for example does:
os.Open('file')
and all other interactions with FS.

Glossary for readers with 'some' but maybe not 'robust' programming experience

I'm noticing terminology that your average Junior developer and even many that have come up in a relatively stable, siloed domain would likely be spotty on. Is it worth a glossary on these or links to definitions? I realize they're not go specific...

If it's wanted, I can help with the leg-work

Examples:

  • DSL
  • Opinionated
  • Domain

Add version of release

Hi,
it would be great if the version of the release is also included in the output file (e.g. PDF), so it is easy to determine which version is currently viewed.

Thanks

Time chapter code gets murky around renaming Game to TexasHoldem

I've been writing code following the text in the time chapter and around L772 things seem to go off the rails a bit in terms of what the text mentions and the state of passing code. Around this paragraph:

This should just be an exercise in copying the tests from the CLI_test into a new set but with less dependencies to set up; so we wont show all the code here (you can always check the full source here) but here is an example of one of the moved tests for reference.

That's not to say that it's incomprehensible or that the diligent reader can't work it out but it does feel markedly different from the rest of the book up until this point. I realize this is vague - I will attempt to fill in further details if I find the time, but I wanted to flag it before I forget. I think anyone who writes the code themselves while reading will understand what I mean.

The main issue I'm finding is that there is a considerable gap and amount of work to get the tests back to green and it seems like the text chugs through it. It seems like there are too many test changes along with creating new things and moving things while in the red state.

Skill: Table Driven Tests

Go's declarative nature can mean a lot of boilerplate involved in preparing a test. One option is to use the TestMain function to set global state used by many tests:

var thing Thing
func TestMain(t *testing.M){
  thing = setup()
}

Avoid this pattern whenever possible. Global state bugs lead to fear, anger and the dark side.

Another approach is to copy and paste code around many similar top level tests. You have certainty that no variable state is shared between tests, with the drawback of extra maintenance costs:

func TestThingDoesXGivenA(t *testing.T) { thing := setup();  ... }
func TestThingDoesXGivenB(t *testing.T) { thing := setup();  ... }
func TestThingDoesYGivenC(t *testing.T) { thing := setup();  ... }

Table driven tests use a loop to avoid duplicating boilerplate. They can be easier to comprehend and easier to maintain, because there's no duplicates of the lines that assert the behavior:

func TestThing(t *testing.T) {
	type testcase struct {
		input, expected string
	}

	testcases := []testcase{
		testcase{
			input:    "a",
			expected: "x",
		},
		testcase{
			input:    "b",
			expected: "x",
		},
		testcase{
			input:    "c",
			expected: "z",
		},
	}
	for _, tc := range testcases {
		t.Run(fmt.Sprintf("%s given %s", tc.expected, tc.input), func(t *testing.T) {
			thing := setup() // or put outside the loop if you're not concerned about shared state
			actual := thing(tc.input)
			if actual != tc.expected {
				t.Fatalf("expected %q got %q", tc.expected, actual)
			}
		})
	}

}

func setup() func(string) string {
	return func(input string) string {
		switch input {
		case "a", "b":
			return "x"
		case "c":
			return "y"
		default:
			return ""
		}
	}
}

The t.Run method allows you to label tests, like a describe block in other languages' tests. go test -v -run 'TestThing/z_given_c' lets you run a specific subtest, which can be nice if you don't want to see log output from other tests or subtests.

Automated check of snippets in the readme files

I have made dozens of mistakes when changing the snippets of Go code in the readme files

Whilst the build.sh will check all of the code examples, it cant check the contents of the markdown files

So it's all manual checking and i am rubbish at that.

There has to be a way to automate it

Reflection Chapter - alternate view on "bad refactor"

Did an in retrospect bad refactor but didn't get too upset about it. By working iteratively with tests it's not such a big deal.

An alternative view would be that in this case the refactoring wasn't pushed far enough. Example:

package main

import "reflect"

type ReportString func(input string)

type getByIndex func(index int) reflect.Value

func Walk(x interface{}, fn ReportString) {
	val := getValue(x)

	switch val.Kind() {
	case reflect.String:
		fn(val.String())
	case reflect.Struct:
		walkByIndex(val.NumField(), val.Field, fn)
	case reflect.Slice, reflect.Array:
		walkByIndex(val.Len(), val.Index, fn)
	case reflect.Map:
		walkByKey(val, fn)
	}
}

func getValue(x interface{}) reflect.Value {
	val := reflect.ValueOf(x)

	if val.Kind() == reflect.Ptr {
		return val.Elem()
	}

	return val
}

func walkByIndex(numberOfValues int, get getByIndex, fn ReportString) {
	for i := 0; i < numberOfValues; i++ {
		Walk(get(i).Interface(), fn)
	}
}

func walkByKey(val reflect.Value, fn ReportString) {
	for _, key := range val.MapKeys() {
		Walk(val.MapIndex(key).Interface(), fn)
	}
}

or possibly even

package main

import "reflect"

type ReportString func(input string)

type fetchValue func(index int) reflect.Value
type initWalk func() (length int, fetch func(index int) reflect.Value)

func Walk(x interface{}, fn ReportString) {
	val := getValue(x)

	switch val.Kind() {
	case reflect.String:
		fn(val.String())
	case reflect.Struct:
		walkAll(structInit(val), fn)
	case reflect.Slice, reflect.Array:
		walkAll(sliceInit(val), fn)
	case reflect.Map:
		walkAll(mapInit(val), fn)
	}
}

func getValue(x interface{}) reflect.Value {
	val := reflect.ValueOf(x)

	if val.Kind() == reflect.Ptr {
		return val.Elem()
	}

	return val
}

func walkAll(init initWalk, fn ReportString) {
	numberOfValues, fetch := init()
	for i := 0; i < numberOfValues; i++ {
		Walk(fetch(i).Interface(), fn)
	}
}

func structInit(container reflect.Value) initWalk {
	return func() (int, func(int) reflect.Value) {
		return container.NumField(), container.Field
	}
}

func sliceInit(container reflect.Value) initWalk {
	return func() (int, func(int) reflect.Value) {
		return container.Len(), container.Index
	}
}

func mapInit(container reflect.Value) initWalk {
	keys := container.MapKeys()
	fetch := func(i int) reflect.Value {
		return container.MapIndex(keys[i])
	}

	return func() (int, func(int) reflect.Value) {
		return len(keys), fetch
	}
}

Aside: The order of the map keys doesn't seem to be guaranteed - every once in a while:

$ go test
--- FAIL: TestWalk (0.00s)
    --- FAIL: TestWalk/Maps (0.00s)
    	reflection_test.go:98: got [Boz Bar], want [Bar Boz]
FAIL
exit status 1
FAIL	_/Users/wheatley/sbox/golang/test-go/12/src	0.006s
$ go version
go version go1.10.3 darwin/amd64
$

amazing job guys

One of the best approaches to teach Golang I've seem

Keep going!

clean tmp file should close first

In IO and sorting chapter, create tmp file helper function should close before remove

`func createTempFile(t *testing.T, initialData string) (io.ReadWriteSeeker, func()) {
t.Helper()

tmpfile, err := ioutil.TempFile("", "db")

if err != nil {
    t.Fatalf("could not create temp file %v", err)
}

tmpfile.Write([]byte(initialData))

removeFile := func() {
    **tmpFile.Close()**
    os.Remove(tmpfile.Name())
}

return tmpfile, removeFile

}`

https://github.com/quii/learn-go-with-tests/blob/0e94809c8a308e995d3f5e80ae43587880991700/io/v3/FileSystemStore_test.go#L22

Automated spelling and grammar check

Ideally it would be good if everyone didn't have to suffer from reading my terrible grammar and spelling and that it was integrated into the travis build.

Whatever it is, it will need to recognise markdown because it'll need to ignore code and code blocks

We would like to translate the project into Chinese

Hello, I'm a gopher, I founded the Go Chinese community https://studygolang.com in 2013. In order to better promote the go language, the introduction of foreign excellent information to China, in November 2017, I organized the GCTT (Go Chinese Translation Team). 2 months ago, I saw your articles about TDD, and GCTT start translating, and later discovered https://github.com/quii/learn-go-with-tests this project, thanks for providing such a good project, GCTT wants to translate it into Chinese, I wonder if we can do that? Looking forward to your reply. Thank you!

Section: Pointers

Ideas

  • Write a test where we want a method to change the value of a thing, but show that by not using pointers it does not change it.
  • Explain how everything in Go is pass by value (i.e everything is copied), so if we wish to change the value of something via a function/method then we will need to pass a copy of a pointer instead. This pointer can then be used to change a value as we intend

Need to cover

  • Talk about design choices, if a thing is "big" then we may want to pass a pointer to it, even if we dont want to modify it. Can an example be made here via benchmarking?

Iteration Chapter - Benchmarking - Clarification

It's not entirely clear here, whether it takes 139 nanoseconds on average or in entirety, it could be deduced from ns/op but would not necessarily be obvious to someone new, nor that the 10000000 is the number of executions as opposed to some other stat.

Might be worth some further explanation?

image

For kicks, I tried the following

func BenchmarkRepeatFlat(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Repeat("a", 10)
	}
}

func BenchmarkRepeatIncr(b *testing.B) {
	for i := 1; i <= b.N; i++ {
		Repeat("a", i)
	}
}

and got
image

not unsurprising, but ... a lesson in how not to be clever

Skill: Dependency Injection of mocks

It's common to test a piece of code that relies on some other type. You can instantiate a "real" version of the dependency and use it in the tests, but that may have costs - it may run slowly, return something different every time, or be complicated to configure. I prefer to use an interface to declare what the dependency does, so I can use a "mock" version of that type in the tests.

Feel free to copy and/or modify http://therealplato.com/posts/soberoctober11/#quick-pattern-dependency-injection . May be worth providing examples both with and without github.com/stretchr/testify/mock

Section: Collections

Made a start with arrays, need to continue into slices. Transition can be motivated by needing varying length arrays, refactor to slices

Should mocking chapter have tests for Sleeper implementation?

In my opinion, I think that the Sleeper implementation test would be very helpful here. However, I am not sure how this would be done in a nice way.

I would love to help with this if I can get just a little guidance on how to handle this in an idiomatic Go way.

Shapes chapter: You can't get the Perimeter of a triangle given base and height

Hi, not sure if this qualifies as an issue. But, I was hoping to see discussion about some things:

  • The chapter defines a Shape interface with the Area() method. If you add another method to the Shape interface, all shapes (ie. rectangle, circle, triangle) have to implement the new method (Perimeter).
  • So it makes sense why there are a lot of 1 method interfaces.
type Shape interface {
    Area() float64
    Perimeter() float64
}

When you go and implement Perimeter for all the shapes, you realize you can't get the perimeter of a triangle with base and height.

I suggest changing the name Triangle to RightTriangle, because the perimeter is defined. Then the discussion can continue.

map chapter

We've got a few chapters in progress that uses maps but have not actually explained them!

Could be a potentially interesting chapter as they can be used in a number of ways

  • Key/Value store (obviously)
  • Sets

Could cover that they are not safe for concurrent use

fmt.Println error in pointers-and-errors.md

There are two fmt.Printlns in pointers-and-errors.md:

  • fmt.Println("address of balance in test is %v \n", &wallet.balance)
  • fmt.Println("address of balance in Deposit is %v \n", &w.balance)

will raise Println call has possible formatting directive %v.

Solution is to update to fmt.Printf: fmt.Printf("address of blance in test is %v \n", &wallet.balance)

implement a real database like postgres

Hi,
I am lost in how to implement postgres with test, I have read and write "Build an application" multi times and want to write a postgresql store, but I don't know how to easily create initialization data and clean them,should I use insert to create init data then clean them after test? I want to know if there is a more elegant way to test the real database.

Thanks lot!

IO and sorting - "Another problem"

After you introduce the need for a tape struct (BTW, you went against your own dicta/modus operandi by writing the implementation first and then the test, even though the heading after "Another problem" is "Write the test first"), my test does not fail with the got 'abc45' want 'abc' problem. Instead, the build fails with:

./FileSystemStore.go:17:18: cannot convert database (type io.ReadWriteSeeker) to type tape

That makes sense to me because you only implemented the Write method.

Going on with the next section and replacing the io.Writer by *os.File, causes the test to fail again with another message (in addition to the one above):

./tape_test.go:12:16: cannot use file (type io.ReadWriteSeeker) as type *os.File in field value: need type assertion

You state "You should be able to fix these problems yourself by now but if you get stuck just check the source code." The problem if one gets stuck is that there's no snapshot of the code at this point (by my reckoning it would have to be something like V6.5). Anyway, I'll give it a try and if needed i'll update this issue further.

Section:Integers - Suggestion

While running go test with the ExampleAdd() function, I observed that if we remove the comment(Output: 6), the test will not execute this function. I checked the go documents and found out
here - https://golang.org/pkg/testing/#hdr-Examples

Example functions without output comments are compiled but not executed

May be we can add this as a note in Integers Section ?

Flags

A few people have asked how to test these.

assertCorrectMessage should accept a *testing.T argument

In the hello_world examples, assertCorrectMessage should accept a *testing.T argument. The way it is currently written, the subtests never fail from an assertion, just TestHello.

v5 should look something like this:

func TestHello(t *testing.T) {

	assertCorrectMessage := func(t *testing.T, got, want string) {
		t.Helper()
		if got != want {
			t.Errorf("got '%s' want '%s'", got, want)
		}
	}

	t.Run("saying hello to people", func(t *testing.T) {
		got := Hello("Chris")
		want := "Hello, Chris"
		assertCorrectMessage(t, got, want)
	})

	t.Run("empty string defaults to 'world'", func(t *testing.T) {
		got := Hello("")
		want := "Hello, World"
		assertCorrectMessage(t, got, want)
	})

}

This will cause the output of go test to be:

--- FAIL: TestHello (0.00s)
    --- FAIL: TestHello/empty_string_defaults_to_'world' (0.00s)
        hello_test.go:23: got 'Hello, ' want 'Hello, World'
FAIL
exit status 1
FAIL    github.com/quii/learn-go-with-tests/hello-world/v5      0.006s

That makes it easier to track down which subtest failed.

Test failed cause refactoring on page 67

On page 67 the Refactor section needs further information because with those changes then test fails in subsequent sections

./dictionary.go:3:8: imported and not used: "errors"
./dictionary.go:16:5: invalid case ErrNotFound in switch on err (mismatched types string and error)
./dictionary.go:19:9: cannot use ErrWordExists (type string) as type error in return argument:
	string does not implement error (missing Error method)
./dictionary.go:34:16: cannot use ErrNotFound (type string) as type error in return argument:
	string does not implement error (missing Error method)
./dictionary_test.go:34:20: cannot use ErrWordExists (type string) as type error in argument to assertError:
	string does not implement error (missing Error method)
./dictionary_test.go:99:20: cannot use ErrNotFound (type string) as type error in argument to assertError:
	string does not implement error (missing Error method)

Missing 'import "fmt"' to make ExampleAdd() work in Integers/Examples

Text in the book says to add the ExampleAdd() function to adder_test.go, however it won't compile because the "fmt" package hasn't been imported into adder_test.go

Easy and simple to fix, perhaps instead it could be an opportunity to suggest to the reader to have a go at fixing the problem before telling them what the fix is.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.