rafaeljusto/redigomock

Accessing redigomock.Conn

Closed this issue · 6 comments

I've been trying for a couple of days to use the connection from redis.Pool in my tests, but am having lots of fail. I've pasted my test code below, with commented out attempts and their error messages. I'd prefer not to have to refactor my code to pass around a connection, as there is a connection attached to the instance of the struct that the method comes with

package rediscache

import (
	"log"
	"os"
	"testing"

	"github.com/gomodule/redigo/redis"
	"github.com/rafaeljusto/redigomock"
	v1 "github.com/shanehowearth/cloudblog/readarticle/integration/grpc/gen/v1"
	"github.com/stretchr/testify/assert"
)

var testR Redis


func TestMain(m *testing.M) {
	log.Print("Test Main")

	conn := redigomock.NewConn()
	mockPool := &redis.Pool{
		// Return the same connection mock for each Get() call.
		Dial:    func() (redis.Conn, error) { return conn, nil },
		MaxIdle: 10,
	}
	log.Printf("TM connection %v", mockPool.Get())
	testR = Redis{pool: mockPool}
	log.Print("Exit test main")
	os.Exit(m.Run())
}

func TestGetByTitle(t *testing.T) {
	log.Print("Enter TestGetByTitle")
	testcases := map[string]struct {
		title string
	}{
		"Happy Path": {title: "Success"},
	}
	for name, tc := range testcases {
		t.Run(name, func(t *testing.T) {
			log.Printf("Calling %s\n", name)
			cmd := testR.pool.Get()
                        // cmd := testR.pool.Get().(redigomock.Conn) // fails with  testR.pool.Get() (value of type github.com/gomodule/redigo/redis.Conn) cannot have dynamic type github.com/rafaeljusto/redigomock.Conn (missing method Close) 
                        // cmd := redigomock.Conn(testR.pool.Get()) // fails with cannot convert testR.pool.Get() (value of type github.com/gomodule/redigo/redis.Conn) to github.com/rafaeljusto/redigomock.Conn 
			// cmd := redigomock.NewConn() // fails with invalid operation: cmd (variable of type *github.com/rafaeljusto/redigomock.Conn) is not an interface 
			log.Printf("Mock cmd: %v", cmd)
			cmd.(redigomock.Conn).Command("HGET", "articles:lookup:title", "Success").Expect(int64(1))
			output := testR.GetByTitle(tc.title)
			assert.Equal(t, &v1.Article{Title: tc.title}, output, "Article returned did not match expected")
		})
	}
}

I think you should use:

cmd := testR.pool.Get().(*redigomock.Conn)

As the redigomock.NewConn() returns a pointer to the type. The Close method is implemented in the pointer receiver.

Perfect, that was what I needed to do. Can I suggest an addition to the pool example in the docs?

So I was a bit premature on thinking this is closed :(

The call produces this (it's the type assertion that's panicking)

panic: interface conversion: redis.Conn is *redis.activeConn, not *redigomock.Conn [recovered]
        panic: interface conversion: redis.Conn is *redis.activeConn, not *redigomock.Conn

goroutine 20 [running]:
testing.tRunner.func1(0xc000136200)
        /usr/local/go/src/testing/testing.go:830 +0x392
panic(0x8a6540, 0xc000134300)
        /usr/local/go/src/runtime/panic.go:522 +0x1b5
github.com/shanehowearth/cloudblog/readarticle/internal/repository/redis.TestGetByTitle.func1(0xc000136200)
        /home/shane/pop/new_flash_bkup/readarticle/internal/repository/redis/connection_test.go:41 +0x3fe
testing.tRunner(0xc000136200, 0xc0000a4820)
        /usr/local/go/src/testing/testing.go:865 +0xc0
created by testing.(*T).Run
        /usr/local/go/src/testing/testing.go:916 +0x35a

Can I suggest an addition to the pool example in the docs?

Sure, feel free to open PRs clarifying the docs. 👍 Thanks!

panic: interface conversion: redis.Conn is *redis.activeConn, not *redigomock.Conn

Can I suggest a simplified scenario? We could drop the TestMain.

func TestGetByTitle(t *testing.T) {
  tests := map[string]struct {
    title string
  }{
    "Happy Path": {title: "Success"},
  }

  conn := redigomock.NewConn()

  for name, tc := range tests {
    t.Run(name, func(t *testing.T) {
      conn.Clear()
      conn.Command("HGET", "articles:lookup:title", "Success").Expect(int64(1))

      testR := Redis{
        pool: &redis.Pool{
          Dial:    func() (redis.Conn, error) { return conn, nil },
          MaxIdle: 10,
        },
      }
      output := testR.GetByTitle(tc.title)
      assert.Equal(t, &v1.Article{Title: tc.title}, output, "Article returned did not match expected")
    })
  }
}

Ok, definitely working now. I'll sort out a docs addition in the morning. Thanks!