Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to properly make dependency injection with ServiceWeaver #419

Closed
Markbnak opened this issue Jun 27, 2023 · 5 comments
Closed

How to properly make dependency injection with ServiceWeaver #419

Markbnak opened this issue Jun 27, 2023 · 5 comments
Assignees

Comments

@Markbnak
Copy link

Markbnak commented Jun 27, 2023

I'm trying to implement the dependency injection pattern in my code.

I need it because we need to mock results from an external API during tests.

Here is a sample of what I'm trying to achieve:

Service calling external data

// get external data service
package service

type GetExternalDataService interface {
	GetData(ctx context.Context, value string)
}

type getExternalDataServiceImpl struct {
	weaver.Implements[]
}

func GetData(ctx context.Context, value string) {
  // getting the actual external data //
}

Service

// service
package service
var Dependency_fn DepFunc

type DepFunc func(ctx context.Context, x string, y string)

type someService interface {
	GetSomeExternalData(ctx context.Context, value string)
}

type someServiceImpl struct {
	weaver.Implements[]
	externalService weaver.Ref[service.GetExternalDataService]
}

func (s *someServiceImpl) GetSomeExternalData(ctx context.Context, value string) {
	// calling external API //
	DepFunc(ctx, "some data")
}

Tests

// tests
package service

func mock_external_data(ctx context.Context, data string) {
  // returns mock data //
}

func setupTest(t *testing.T) {
	t.Helper()
	Dependency_fn = mock_external_data
}


func TestGetSomeExternalData(t *testing.T) {
	setupTest(t)

	runner := weavertest.Local
	runner.Test(t, func(t *testing.T, rate RateService) {

		ctx := context.Background()
		got, err := service.GetSomeExternalData(ctx, "some value")
		if err != nil {
			t.Fatal(err)
		}

		if want := what_I_want; !got.Equal(want) {
			t.Fatalf("got %q, want %q", got, want)
		}
	})
}

The calling service

// other service
package secondService

type SecondService struct {
  SendReceivedData(ctx context.Context)
}

type secondServiceImpl struct {
  SendReceivedData(ctx context.Context)
  service weaver.Ref[service.someService]
}

func (s *secondServiceImpl) Init(ctx context.Context) error {
  s.service.Dependency_fn = service.GetExternalDataService
}


func (s *secondServiceImpl) SendReceivedData(ctx context.Context) {
  received, err := s.service.GetSomeExternalData(ctx, "some data")
  // other code //
}

The whole problem is how to tell the service package which Dependency_fn function to use when calling it from secondService package.

The tests I developed work perfectly and I am able to use the mock function.

I read a similar issue: #188

In the discussion it is suggested to use weaver.Get[Foo], but this provides me compilation errors such as:
undefined: weaver.get

For these examples I tried versions v0.13.0 and v0.16.0.

@mwhittaker
Copy link
Member

Hi @Markbnak, does weavertest.Fake suit your use case? You can see an example of weavertest.Fake in use here. Let me know if you have any questions about how it works and how you're supposed to use it.

@mwhittaker mwhittaker self-assigned this Jun 27, 2023
@Markbnak
Copy link
Author

Thank you for sharing this, I haven't seen that feature in the documentation.

@Markbnak
Copy link
Author

@mwhittaker, I think that this suits my use case.
I would appreciate more details on how to use it.
Maybe an other example could help me and the community.
I tried to implement this logic for my code, but the faked component is not being executed, instead the real component is executed during tests.

@Markbnak
Copy link
Author

@mwhittaker I managed to resolve my issue, this code example was what I was looking for. I hope you will document that on your website.

mwhittaker added a commit that referenced this issue Jun 29, 2023
In Issue #419, @Markbnak pointed out that our documentation on fakes is
a little lacking. I agree. This PR adds a simple example of faking and
adds documentation to the website on faking.
@mwhittaker
Copy link
Member

Awesome! I opened #430 for this as well!

mwhittaker added a commit that referenced this issue Jul 5, 2023
In Issue #419, @Markbnak pointed out that our documentation on fakes is
a little lacking. I agree. This PR adds a simple example of faking and
adds documentation to the website on faking.
mwhittaker added a commit that referenced this issue Jul 5, 2023
In Issue #419, @Markbnak pointed out that our documentation on fakes is
a little lacking. I agree. This PR adds a simple example of faking and
adds documentation to the website on faking.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants