1
\$\begingroup\$

I have a standard table-test unit-test in Go. How can I make it simpler, easy to read and succinct?

I'm looking suggestions for: Structural refactoring. Less and simple code to achieve the same thing.

test.go

func Test_Parses_Books(t *testing.T) {
 books := xmlDoc.Book
 type tester struct {
 texts []Text
 bookID int
 categoryLen int
 }
 getBookTest := func(i int) tester {
 book := books[i]
 return tester{
 texts: book.BookNames,
 bookID: book.BookID,
 categoryLen: len(book.Categories),
 }
 }
 booklen := len(books)
 if booklen != 4 {
 t.Errorf("expected: 4. got: %d", booklen)
 }
 var testTable = []struct {
 expected tester
 actual tester
 }{{
 expected: tester{
 texts: []Text{
 {"BOOK", "TV"},
 {"en", "TV"}},
 bookID: 1,
 categoryLen: 2},
 actual: getBookTest(0),
 }, {
 expected: tester{
 texts: []Text{
 {"BOOK", "PS4"},
 {"en", "PS4"}},
 bookID: 5,
 categoryLen: 2},
 actual: getBookTest(1),
 }, {
 expected: tester{
 texts: []Text{
 {"BOOK", "XBOX"},
 {"en", "XBOX"}},
 bookID: 22,
 categoryLen: 1},
 actual: getBookTest(2),
 }, {
 expected: tester{
 texts: []Text{
 {"BOOK", "PS3"},
 {"en", "PS3"}},
 bookID: 17,
 categoryLen: 1},
 actual: getBookTest(3),
 }}
 for i, test := range testTable {
 if !reflect.DeepEqual(test.expected, test.actual) {
 t.Errorf("\nexpected: [%d]\n\t%#v.\ngot:\n\t%#v",
 i, test.expected, test.actual)
 }
 }
}
asked May 20, 2017 at 19:04
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

The actual values should not be part of the table since it is much easier to refer to them as books[i] in the loop.

The type tester has a bad name since that name sounds active, as if the type could actually test something. Choose a more passive name, such as BookInfo.

The field tester.categoryLen should be named categoriesLen since asking for the length of a single category doesn't make sense.

The function getBookTest should be named extractInfo or something similar.

After renaming and reorganizing the code, it looks like this. But since you did not provide any real test data, I can only hope that it runs fine, I could not actually test it.

import (
 "reflect"
 "testing"
)
type Document struct {
 Book []Book
}
type Book struct {
 BookNames []string
 BookID int
 Categories []Category
}
type Text string
type Category struct{}
var xmlDoc Document
func Test_Parse_Books(t *testing.T) {
 books := xmlDoc.Book
 type BookInfo struct {
 Texts []Text
 ID int
 CategoriesLen int
 }
 extractInfo := func(book Book) BookInfo {
 return BookInfo{
 Texts: book.BookNames,
 ID: book.BookID,
 CategoriesLen: len(book.Categories),
 }
 }
 newBookInfo := func(title string, id int, categoriesLen int) BookInfo {
 return BookInfo{
 Texts: []Text{
 {"BOOK", title},
 {"en", title}},
 ID: id,
 CategoriesLen: categoriesLen}
 }
 booklen := len(books)
 if booklen != 4 {
 t.Errorf("expected: 4. got: %d", booklen)
 }
 var expectedData = []BookInfo{
 newBookInfo("TV", 1, 2),
 newBookInfo("PS4", 5, 2),
 newBookInfo("XBOX", 22, 1),
 newBookInfo("PS3", 17, 1)}
 for i, expected := range expectedData {
 actual := extractInfo(books[i])
 if !reflect.DeepEqual(expected, actual) {
 t.Errorf("wrong value for book %d\nexp: %#v\ngot: %#v",
 i, expected, actual)
 }
 }
}
answered May 21, 2017 at 6:49
\$\endgroup\$
0
1
\$\begingroup\$

I'm going to use the following refactoring for the: Ease-of-read, extensibility and brevity.

Because, I believe, defining new types and function__s__ (single, short one seems ok_) inside tests make readability and one-look understandability harder. Tests are meant for documentation as well. They should be clear instantly.

refactored_test.go

// asserts use testify for brevity
func Test_Parse_Books(t *testing.T) {
 assert := assert.New(t)
 texts := func(text string) []Text {
 return []Text{{"BOOK", text}, {"en", text}}
 }
 exps := []Book{
 {
 Texts: texts("TV"),
 Categories: make([]Category, 2),
 ID: 1},
 {
 Texts: texts("PS4"),
 Categories: make([]Category, 2),
 ID: 5},
 {
 Texts: texts("XBOX"),
 Categories: make([]Category, 1),
 ID: 22},
 {
 Texts: texts("PS3"),
 Categories: make([]Category, 1),
 ID: 17}}
 acts := xmlDoc.Books
 assert.Equal(4, len(acts))
 for i, exp := range exps {
 act := acts[i]
 assert.Equal(len(act.Categories), len(exp.Categories))
 assert.Equal(act.ID, exp.ID)
 assert.Equal(act.Texts, exp.Texts)
 }
}
answered May 22, 2017 at 18:11
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.