0
\$\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)
            }
    }
}
\$\endgroup\$
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)
        }
    }
}
\$\endgroup\$
0
\$\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)
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.