다음과 같이 쓸 수 있을 것이다.

  1. 먼저 인터페이스를 작성한다.
package mqevent

import amqp "github.com/rabbitmq/amqp091-go"

type MQ interface {
	MqChannel() (*amqp.Channel, error)
	PublishToExchange(orgid, userid, messageType, message string, ch *amqp.Channel) error
	DeleteQueue(orgid, userid, queueNumber string, ch *amqp.Channel) error
	DeclareExchange(orgid string, ch *amqp.Channel) error
	DeclareQueue(orgid, userid, queueNumber string, ch *amqp.Channel) (amqp.Queue, error)
	BindQueue(orgid, userid string, que amqp.Queue, ch *amqp.Channel) error
	PublishToPublic(orgid, userid string, ch *amqp.Channel) error
	CountQueueBoundedToExchange(orgId string) (int, error)
	DeclareDeadQue(ch *amqp.Channel) (amqp.Queue, error)
	BindDeadQue(que amqp.Queue, ch *amqp.Channel) error
}

var Mqutil MQ
  1. 배포 환경에서 사용되는 실제 함수들은 테스팅이 쉽도록 따로 모음집으로 구현한다.

    이때 테스팅을 용이하게 하기위해 진짜로 테스트하고 싶은 기능만 포함되도록 함수를 구현해야하는것이 중요하다

package mqConnection

...

type MQ struct {
}

func (q *MQ) MqChannel() (*amqp.Channel, error) {
	ch, err := connection.RabbitConn.Channel()
	if err != nil {
		return nil, err
	}
	return ch, nil
}

func (q *MQ) PublishToExchange(orgid, userid, message, messageType string, ch *amqp.Channel) error {

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err := ch.PublishWithContext(ctx,
		orgid,                            // exchange
		orgid+"."+userid+"."+messageType, // routing key
		false,                            // mandatory
		false,                            // immediate
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		})
	if err != nil {
		return err
	}
	return nil
}

....
  1. spy 함수를 만든다. 입력인자를 주면 내가 원하는 출력값을 리턴하도록 단순하게 구현하면된다. (jest.spy처럼!)
package mqConnection

import (
	amqp "github.com/rabbitmq/amqp091-go"
)

type MockMQ struct {
}

func (q *MockMQ) MqChannel() (*amqp.Channel, error) {
	return nil, nil
}

func (q *MockMQ) PublishToExchange(orgid, userid, message, messageType string, ch *amqp.Channel) error {
	return nil
}

...
  1. 그리고 실제 테스트에서는 아래와 같이 활용할 수 있겠다.
package application

import (
	"bytes"
	"fmt"
	"mqlistener/pkg/mqevent"
	"mqlistener/pkg/mqevent/mqConnection"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestPublishQue(t *testing.T) {
	**mqevent.Mqutil = &mqConnection.MockMQ{} //모든 메서드를 다 mock했음:) 이게다임**

	//나머지는 table driven test 방식대로 하면됨.
	tests := []struct {
		name               string
		orgId              string
		userId             string
		queueNumber        string
		message            string
		messageType        string
		resign             bool
		expectedStatusCode int
	}{
		{"PublishSuccess", "h00002", "hiosi", "1", "disconnect", "disconnect", true, http.StatusCreated},
	}

	for _, e := range tests {
		w := httpPublishReq(e.orgId, e.userId, e.queueNumber, e.message, e.messageType, e.resign)

		if e.expectedStatusCode != w.Result().StatusCode {
			t.Errorf("for %s: expected status %v, but got %v", e.name, e.expectedStatusCode, w.Result().StatusCode)
		}

	}
}

func httpPublishReq(orgid, userid, queueNumber, message, messageType string, resign bool) *httptest.ResponseRecorder {
	r := SetUpRouter()
	r.POST("/publishQue", PublishQueInfo)
	jsonBody := []byte(fmt.Sprintf(`{"orgId": "%v", "userId":"%v", "queueNumber": "%v","message": "%v", "messageType": "%v", "resign": %v}`, orgid, userid, queueNumber, message, messageType, resign))
	bodyReader := bytes.NewReader(jsonBody)
	req, _ := http.NewRequest("POST", "/publishQue", bodyReader)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

배포 환경에서 쓰는 코드

package application

import (
	"encoding/json"
	"errors"
	"mqlistener/pkg/mqevent"
	"mqlistener/pkg/request"
	"net/http"

	"github.com/gin-gonic/gin"
)

func PublishQueInfo(c *gin.Context) {
	var req *http.Request = c.Request

	auth := new(AuthPayload)
	err := json.NewDecoder(req.Body).Decode(auth)
	if err != nil {
		request.BadRequest("사용자 정보를 바르게 입력하세요", c)
		return
	}
	//MessageType: public private
	//Message: disconnect, other messages....

	queueName, err := PublishQue(auth.OrgId, auth.UserId, auth.QueueNumber, auth.Message, auth.MessageType, auth.Resign)
	if err != nil {
		request.BadRequest("존재하지 않는 큐 입니다.", c)
		return
	}

	request.CreatedQue("큐에 메세지를 전달하였습니다", queueName, c)
}

func PublishQue(orgid, userid, queueNumber, message, messageType string, resign bool) (string, error) {

	err := checkMessageType(messageType)
	if err != nil {
		return "", err
	}

	ch, err := mqevent.Mqutil.MqChannel()
	if err != nil {
		return "", err
	}

	err = mqevent.Mqutil.PublishToExchange(orgid, userid, message, messageType, ch)
	if err != nil {
		return "", err
	}

	queueName := orgid + "." + userid + "." + queueNumber
	return queueName, nil
}

func checkMessageType(messageType string) error {
	if messageType != "disconnect" && messageType != "public" && messageType != "private" {
		return errors.New("messageType이 틀렸습니다")
	}
	return nil
}