Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid import cycles in mock generation?

Tags:

go

Simple example.

I have package xxx. This package contains:

  • struct A
  • interface B which is a field of A
  • struct C which is an argument in method of B

    type A struct {
        SomeField B
    }
    
    type B interface {
        SomeMethod(c C)
    }
    

Now imagine I want to create unit test for structure A and mock dependency B. For creating mock I am using mock generator. All mocks are stored in the common "mocks" folder.

The problem is that generated mock has a dependency on xxx package. This is happening because SomeMethod of interface B has argument xxx.C.

Whenever I try to import my mock structure in a_test.go it fails because of cycle import problem. xxx package importing mocks package in the a_test.go. and mocks package imports xxx package in my generated mock.

I need a peace of advice, what is the best workaround for this? Maybe my approach is not idiomatic enough. Where do you store your mocks?

like image 721
RhinoLarva Avatar asked Jun 22 '18 10:06

RhinoLarva


People also ask

How do you stop import cycles?

To avoid the cyclic dependency, we must introduce an interface in a new package say x. This interface will have all the methods that are in struct A and are accessed by struct B.

How do I fix import cycle not allowed in test?

According to above explanation, put the tests within the same package will always got into the import cycle problem, and the solution is to move it to another package.

What is import cycle?

Explanation: Import cycles. It is possible to write packages so that package A imports package B and package B imports package A. ... If you make sure that, in any import cycle, at least one of the imports is in the implementation part of a package, you will not encounter any trouble.


2 Answers

You need to put your test under a different package.

a.go is under package xxx

a_test.go is under package xxx_test

a_mock.go is under package xxx_mock

This way a_test.go will be dependent on xxx and xxx_mock and will not cause dependency cycle.

Also, a.go and a_test.go can be under the same folder, like this:

xxx/
  - a.go
  - a_test.go
mock/
  - a_mock.go
like image 84
fallaway Avatar answered Sep 18 '22 10:09

fallaway


Since

  1. interface
  2. struct
  3. user code
  4. unit test for the user code

are all in the same package, the interface should be considered as "in-package" interface, which is invisible for code in other package. So, the mock for this interface should be IN THE SAME PACKAGE as the interface itself.

Conclusion:

  1. interface
  2. struct
  3. user code
  4. unit test for the user code
  5. mock for the interface

PUT ALL OF THEM IN THE SAME PACKAGE.

So put the mock code generated by gomock into the same package as the interface, but not "mock" package. Example(windows version):

mockgen -source=.\foo\bar.go -destination=.\foo\bar_mock.go -package=foo
like image 42
seedjyh Avatar answered Sep 17 '22 10:09

seedjyh