Как в Go проверить правильность вызова фиктивной зависимости.
Если у меня есть структура, которая принимает интерфейс для зависимости, после инъекции я хочу иметь возможность протестировать исходный фиктивный объект.
В моем текущем коде в этом примере я не вижу, что значение структуры изменилось. Если я изменю свой код для передачи по ссылке, это вызовет ошибку:
s.simpleInterface.Call undefined (тип * SimpleInterface - это указатель на интерфейс, а не на интерфейс)
type SimpleInterface interface {
Call()
}
type Simple struct {
simpleInterface SimpleInterface
}
func (s Simple) CallInterface() {
s.simpleInterface.Call()
}
type MockSimple struct {
hasBeenCalled bool
}
func (ms MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
Я попробовал это и начал получать ошибку MockSimple не реализует SimpleInterface (метод Call имеет приемник указателя)
Вот почему вам нужно применить изменение, упомянутое в последнем предложении моего предыдущего комментария.
Попробуйте переключить закомментированную строку здесь: play.golang.com/p/3FZwgT4Vhjs. Один компилирует другой - нет.
Ах да, извинения!

Я вижу три простых способа исправить это:
1- Измените подпись метода Call, чтобы получить указатель на MockSimple, и при создании экземпляра простой структуры укажите адрес вашего макета:
func (ms *MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: &ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
2- Не самое чистое решение, но все же работает. Используйте его, если вы действительно не можете использовать №1. Объявите hasBeenCalled в другом месте и измените свой MockSimple так, чтобы он содержал указатель на него:
type MockSimple struct {
hasBeenCalled *bool
}
func (ms MockSimple) Call() {
*ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
hasBeenCalled := false
ms := MockSimple{&hasBeenCalled}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
3- Вероятно, действительно плохое решение: с использованием глобальных переменных, поэтому я бы использовал его только в крайнем случае (всегда избегайте глобального состояния). Сделайте hasBeenCalled глобальным и измените его из метода.
var hasBeenCalled bool
type MockSimple struct{}
func (ms MockSimple) Call() {
hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
Ваше здоровье!
Как и выше, первое решение начинает вызывать ошибку. MockSimple не реализует SimpleInterface (метод Call имеет приемник указателя)
Ваше второе решение было лучшей реализацией
@CharlesBryant, вам действительно следует использовать 1-е решение, если вы добавите & перед ms при настройке поля simpleInterface, вы не получите ошибку, которую, как вы утверждаете, получаете. Оба решения 2 и 3 нетрадиционны и не имеют преимущества перед 1.
Всегда используйте приемник указателя всякий раз, когда ваш метод должен изменить состояние этого приемника. то есть
func (ms *MockSimple) Call() {. Если вы этого не сделаете, то изменения вmsне будут видны за пределами тела метода, потому чтоmsна самом деле является копией экземпляра, для которого был вызван метод, а не самим экземпляром. Это изменение также потребует использования указателяMockSimpleдля установкиSimple.simpleInterface. то естьSimple{simpleInterface: &ms}.