-
Notifications
You must be signed in to change notification settings - Fork 337
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
Refactor controller_tests to use builder pattern #376
Comments
/help |
@msau42: Please ensure the request meets the requirements listed here. If this request no longer meets these requirements, the label can be removed In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Issues go stale after 90d of inactivity. If this issue is safe to close now please do so with Send feedback to sig-testing, kubernetes/test-infra and/or fejta. |
/lifecycle frozen |
/assign |
Hi @msau42 could you let me know, here what we mean when we are talking on |
Hi @Kartik494, in some of the initial examples I referenced, the test case has a lot of conditional statements about different scenarios, and are adjusting the test inputs based off of that. I think it makes the test hard to read and understand because you need to run through all these conditionals to figure out what the input object looks like. Instead, I think it would be better if the test took the actual object as an input. Here is an example:
You can see that the test case itself is very short and and simple compared to the original examples, and it's very clear what objects are being tested. I suggested the builder pattern as a way to reduce duplicate lines for the input object, but it doesn't have to be done this way. I think what I had in mind was a method that produces a basic input object, and then chain that with methods that customize different fields for the test case. Here's a nice post I found explaining a couple of options: https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/ I couldn't find an example of a unit test that does this, but you can see some libraries that provide "WithX()" methods that modify the input object: https://github.com/kubernetes-csi/csi-lib-utils/blob/master/leaderelection/leader_election.go#L124 Hope this is helpful, let me know if you have more questions! |
Hi @msau42 So for Every Conditional statement here
Should i provide Methods Like this
and when i study the article (https://www.calhoun.io/using-functional-options-instead-of-method-chaining-in-go/) i get to know that Like we have Pattern builder as part of creational design pattern in java, we should implement |
Hi @Kartik494, so I think the final end goal should be to remove the conditionals in the testcase that adjust the input object. Using a build/chaining api to construct the input is optional. Maybe for now to keep it simple, start with passing the entire object as input, and we can see if adding some constructors would be useful or not. |
Hi @msau42 Thanks for the response, i will be changing this as suggested and raising a PR Accordingly |
@Kartik494 I'd frame the problem like this, we have a list of test cases
It looks like external-provisioner/pkg/controller/controller_test.go Lines 2209 to 2236 in a9b470d
Ideally when Imagine that the creation of a single test case is abstracted by a function: // TestCaseBuilder returns testCase Object
func TestCaseBuilder() provisioningTestcase {
tc := provisioningTestcase{ ... }
return tc
}
// usage
tc := TestCaseBuilder()
// tc is not very well defined at this point, we might need to add some additional properties
if tc.foo {
tc.bar = "dummy"
}
if tc.hello {
tc.world = "dummy"
} Instead of adding if statements outside like in the example we accept functions that will encapsulate that behavior for us: type ProvisioningTestCaseOption func(*provisioningTestcase) *provisioningTestcase
// TestCaseBuilder returns testCase Object
func TestCaseBuilder(...options ProvisioningTestCaseOption) provisioningTestcase {
// build object as before
tc := &provisioningTestcase{ ... }
for option := range options {
tc = option(tc)
}
return tc
}
func WithBar() ProvisioningTestCaseOption {
return func(tc *provisioningTestCase) *provisioningTestCase {
if tc.foo {
tc.bar = "dummy"
}
return tc
}
}
func WithWorld() ProvisioningTestCaseOption {
return func(tc *provisioningTestCase) *provisioningTestCase {
if tc.hello {
tc.world = "dummy"
}
return tc
}
}
// usage
tc := TestCaseBuilder(WithBar(), WithWorld())
// tc is very well defined at this point That's one of doing it, I learned this from https://github.com/grpc/grpc-go/blob/62adda2ece5ec803c824c5009b83cea86de5030d/examples/helloworld/greeter_client/main.go#L39 you can use the builder pattern too |
@mauriciopoppe Thanks for the response, if i understood it correctly here you are asking for making a test case Builder for Thanks |
For example here you mentioned a function above so here the function withBar() should be a object created from struct objects
|
yes we could have a builder for the |
@msau42 @mauriciopoppe I am interested in working on this issue and would like to take it over. If there is no problem, could you please assign me to this issue? Thank you in advance. |
@hshitomi you can create a minimal PR where you show what the proposed change is going to look like in the description, you can follow #376 (comment) |
@mauriciopoppe Thank you for your quick reply. Also, thank you for sharing the directions. That was very helpful. Yes, I plan to create a draft PR to start our conversation and confirm that I am on the right track, hopefully, tonight. I am currently focusing on the provisioning test cases. I removed the if statements from Is it okay for me to open a draft PR on this issue while I am not assigned to this issue? |
/assign |
Fixes broken link CONTRIBUTING.md
Provision and snapshot tests have a lot of logic built into the test case itself to construct input objects to the functions. For examples:
external-provisioner/pkg/controller/controller_test.go
Line 1487 in 16a2da3
external-provisioner/pkg/controller/controller_test.go
Line 2020 in 16a2da3
I think it would be cleaner to refactor these tests to use a builder pattern and construct the input object when defining the test cases.
The text was updated successfully, but these errors were encountered: