How to unit test methods which using static methods?Static methods or static functions?How do you unit test...
Was it really unprofessional of me to leave without asking for a raise first?
Find the radius of the hoop.
What is an example of of idiomatic "typed" WolframScript?
Comment traduire « That screams X »
Can one use the present progressive or gerund like an adjective?
How can a valley surrounded by mountains be fertile and rainy?
How receiver knows the exact frequency in the channel to "listen to"?
Are all commands with an optional argument fragile?
Different budgets within roommate group
What do you call a notepad used to keep a record?
How could a satellite follow earth around the sun while staying outside of earth's orbit?
How to get a character's limb regrown at 3rd level?
How can I deal with extreme temperatures in a hotel room?
What will happen if I checked in for another room in the same hotel, but not for the booked one?
What game is this character in the Pixels movie from?
Single level file directory
Can European countries bypass the EU and make their own individual trade deal with the U.S.?
Do home values typically rise and fall at a consistent percent?
Adjective for 'made of pus' or 'corrupted by pus' or something of something of pus
Which is better for keeping data: primary partition or logical partition?
Does a Hand Crossbow with the Repeating Shot Infusion still require a Free Hand to use?
Why were the first airplanes "backwards"?
How could an armless race establish civilization?
Do the 26 richest billionaires own as much wealth as the poorest 3.8 billion people?
How to unit test methods which using static methods?
Static methods or static functions?How do you unit test private methods?Interfacing application code with unit testsCorrect Seam for StubReal time unit testing - or “how to mock now”How to unit test static void methods?Using static methods in layered architectureStatic methods and testabilityIs it good practice to stub an object not because it is slow, but to prevent testing it twice?Which code to unit-test?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
Let's assume I wrote an extension method in c# for byte arrays which encodes them into hex strings, as follows:
public static class Extensions
{
public static string ToHex(this byte[] binary)
{
const string chars = "0123456789abcdef";
var resultBuilder = new StringBuilder();
foreach(var b in binary)
{
resultBuilder.Append(chars[(b >> 4) & 0xf]).Append(chars[b & 0xf]);
}
return resultBuilder.ToString();
}
}
I could test the method above using nunit as follows:
[Test]
public void TestToHex_Works()
{
var bytes = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
Assert.AreEqual("0123456789abcdef", bytes.ToHex());
}
If I use the Extensions.ToHex inside my project, let's assume in Foo.Do method as follows:
public class Foo
{
public bool Do(byte[] payload)
{
var data = "ES=" + payload.ToHex() + "ff";
// ...
return data.Length > 5;
}
// ...
}
Then all tests of Foo.Do will depend on the success of TestToHex_Works.
Using free functions in c++ the outcome will be the same: tests that test methods that use free functions will depend on the success of free function tests.
How can I handle such situations? Can I somehow resolve these test dependencies? Is there a better way to test the code snippets above?
unit-testing static-methods
add a comment |
Let's assume I wrote an extension method in c# for byte arrays which encodes them into hex strings, as follows:
public static class Extensions
{
public static string ToHex(this byte[] binary)
{
const string chars = "0123456789abcdef";
var resultBuilder = new StringBuilder();
foreach(var b in binary)
{
resultBuilder.Append(chars[(b >> 4) & 0xf]).Append(chars[b & 0xf]);
}
return resultBuilder.ToString();
}
}
I could test the method above using nunit as follows:
[Test]
public void TestToHex_Works()
{
var bytes = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
Assert.AreEqual("0123456789abcdef", bytes.ToHex());
}
If I use the Extensions.ToHex inside my project, let's assume in Foo.Do method as follows:
public class Foo
{
public bool Do(byte[] payload)
{
var data = "ES=" + payload.ToHex() + "ff";
// ...
return data.Length > 5;
}
// ...
}
Then all tests of Foo.Do will depend on the success of TestToHex_Works.
Using free functions in c++ the outcome will be the same: tests that test methods that use free functions will depend on the success of free function tests.
How can I handle such situations? Can I somehow resolve these test dependencies? Is there a better way to test the code snippets above?
unit-testing static-methods
3
Then all tests of Foo.Do will depend on the success of TestToHex_works-- So? You don't have classes that depend on the success of other classes?
– Robert Harvey♦
9 hours ago
2
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
The only downside of this code using static functions is that you can’t easily use something else thantoHex(or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.
– Steve Chamaillard
8 hours ago
2
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
2
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago
add a comment |
Let's assume I wrote an extension method in c# for byte arrays which encodes them into hex strings, as follows:
public static class Extensions
{
public static string ToHex(this byte[] binary)
{
const string chars = "0123456789abcdef";
var resultBuilder = new StringBuilder();
foreach(var b in binary)
{
resultBuilder.Append(chars[(b >> 4) & 0xf]).Append(chars[b & 0xf]);
}
return resultBuilder.ToString();
}
}
I could test the method above using nunit as follows:
[Test]
public void TestToHex_Works()
{
var bytes = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
Assert.AreEqual("0123456789abcdef", bytes.ToHex());
}
If I use the Extensions.ToHex inside my project, let's assume in Foo.Do method as follows:
public class Foo
{
public bool Do(byte[] payload)
{
var data = "ES=" + payload.ToHex() + "ff";
// ...
return data.Length > 5;
}
// ...
}
Then all tests of Foo.Do will depend on the success of TestToHex_Works.
Using free functions in c++ the outcome will be the same: tests that test methods that use free functions will depend on the success of free function tests.
How can I handle such situations? Can I somehow resolve these test dependencies? Is there a better way to test the code snippets above?
unit-testing static-methods
Let's assume I wrote an extension method in c# for byte arrays which encodes them into hex strings, as follows:
public static class Extensions
{
public static string ToHex(this byte[] binary)
{
const string chars = "0123456789abcdef";
var resultBuilder = new StringBuilder();
foreach(var b in binary)
{
resultBuilder.Append(chars[(b >> 4) & 0xf]).Append(chars[b & 0xf]);
}
return resultBuilder.ToString();
}
}
I could test the method above using nunit as follows:
[Test]
public void TestToHex_Works()
{
var bytes = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
Assert.AreEqual("0123456789abcdef", bytes.ToHex());
}
If I use the Extensions.ToHex inside my project, let's assume in Foo.Do method as follows:
public class Foo
{
public bool Do(byte[] payload)
{
var data = "ES=" + payload.ToHex() + "ff";
// ...
return data.Length > 5;
}
// ...
}
Then all tests of Foo.Do will depend on the success of TestToHex_Works.
Using free functions in c++ the outcome will be the same: tests that test methods that use free functions will depend on the success of free function tests.
How can I handle such situations? Can I somehow resolve these test dependencies? Is there a better way to test the code snippets above?
unit-testing static-methods
unit-testing static-methods
asked 9 hours ago
AkiraAkira
1341 gold badge1 silver badge6 bronze badges
1341 gold badge1 silver badge6 bronze badges
3
Then all tests of Foo.Do will depend on the success of TestToHex_works-- So? You don't have classes that depend on the success of other classes?
– Robert Harvey♦
9 hours ago
2
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
The only downside of this code using static functions is that you can’t easily use something else thantoHex(or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.
– Steve Chamaillard
8 hours ago
2
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
2
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago
add a comment |
3
Then all tests of Foo.Do will depend on the success of TestToHex_works-- So? You don't have classes that depend on the success of other classes?
– Robert Harvey♦
9 hours ago
2
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
The only downside of this code using static functions is that you can’t easily use something else thantoHex(or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.
– Steve Chamaillard
8 hours ago
2
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
2
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago
3
3
Then all tests of Foo.Do will depend on the success of TestToHex_works -- So? You don't have classes that depend on the success of other classes?– Robert Harvey♦
9 hours ago
Then all tests of Foo.Do will depend on the success of TestToHex_works -- So? You don't have classes that depend on the success of other classes?– Robert Harvey♦
9 hours ago
2
2
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
The only downside of this code using static functions is that you can’t easily use something else than
toHex (or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.– Steve Chamaillard
8 hours ago
The only downside of this code using static functions is that you can’t easily use something else than
toHex (or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.– Steve Chamaillard
8 hours ago
2
2
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
2
2
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago
add a comment |
2 Answers
2
active
oldest
votes
Then all tests of
Foo.Dowill depend on the success ofTestToHex_Works.
Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.
You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?
The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
add a comment |
Exactly. And this is one of the problems with static methods, another one being that OOP is a much better alternative in most situations.
This is also one of the reasons Dependency Injection is used.
In your case, you may prefer having a concrete converter that you inject into a class which needs a conversion of some values to hexadecimal. An interface, implemented by this concrete class, would define the contract required to convert the values.
Not only would you be able to test your code easier, but you'll also be able to swap implementations later (since there are lots of other possible ways of converting values to hexadecimal, some of them producing different outputs).
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
@ArseniMourzenko so when injecting a calculator class implementing amultiplymethod, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying istoHexis very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.
– Steve Chamaillard
7 hours ago
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case wheretoHexis used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?
– Steve Chamaillard
6 hours ago
|
show 9 more comments
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "131"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f393870%2fhow-to-unit-test-methods-which-using-static-methods%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Then all tests of
Foo.Dowill depend on the success ofTestToHex_Works.
Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.
You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?
The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
add a comment |
Then all tests of
Foo.Dowill depend on the success ofTestToHex_Works.
Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.
You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?
The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
add a comment |
Then all tests of
Foo.Dowill depend on the success ofTestToHex_Works.
Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.
You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?
The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.
Then all tests of
Foo.Dowill depend on the success ofTestToHex_Works.
Yes. That's why you have tests for TextToHex. If those tests pass, the function meets the spec defined in those tests. So Foo.Do can safely call it and not worry about it. It's covered already.
You could add an interface, make the method an instance method and inject it into Foo. Then you could mock TextToHex. But now you have to write a mock, which may function differently. So you'll need an "integration" test to bring the two together to ensure the parts really work together. What has that achieved other than making things more complex?
The idea that unit tests should test parts of your code in isolation from other parts is a fallacy. The "unit" in a unit test is an isolated unit of execution. If two tests can be run simultaneously without affecting each other, then they run in isolation and so are unit tests. Static functions that are fast, do not have a complex set up and have no side effects such as your example are therefore fine to use directly in unit tests. If you have code that is slow, complex to set up or has side effects, then mocks are useful. They should be avoided elsewhere though.
answered 8 hours ago
David ArnoDavid Arno
30.4k7 gold badges63 silver badges98 bronze badges
30.4k7 gold badges63 silver badges98 bronze badges
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
add a comment |
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
You make a pretty good argument for "test-first" development. Mocking exists in part because code gets written in such a way that it is too hard to test, and if you write your tests first, you force yourself to write code that is more easily testable.
– Robert Harvey♦
7 hours ago
add a comment |
Exactly. And this is one of the problems with static methods, another one being that OOP is a much better alternative in most situations.
This is also one of the reasons Dependency Injection is used.
In your case, you may prefer having a concrete converter that you inject into a class which needs a conversion of some values to hexadecimal. An interface, implemented by this concrete class, would define the contract required to convert the values.
Not only would you be able to test your code easier, but you'll also be able to swap implementations later (since there are lots of other possible ways of converting values to hexadecimal, some of them producing different outputs).
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
@ArseniMourzenko so when injecting a calculator class implementing amultiplymethod, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying istoHexis very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.
– Steve Chamaillard
7 hours ago
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case wheretoHexis used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?
– Steve Chamaillard
6 hours ago
|
show 9 more comments
Exactly. And this is one of the problems with static methods, another one being that OOP is a much better alternative in most situations.
This is also one of the reasons Dependency Injection is used.
In your case, you may prefer having a concrete converter that you inject into a class which needs a conversion of some values to hexadecimal. An interface, implemented by this concrete class, would define the contract required to convert the values.
Not only would you be able to test your code easier, but you'll also be able to swap implementations later (since there are lots of other possible ways of converting values to hexadecimal, some of them producing different outputs).
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
@ArseniMourzenko so when injecting a calculator class implementing amultiplymethod, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying istoHexis very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.
– Steve Chamaillard
7 hours ago
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case wheretoHexis used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?
– Steve Chamaillard
6 hours ago
|
show 9 more comments
Exactly. And this is one of the problems with static methods, another one being that OOP is a much better alternative in most situations.
This is also one of the reasons Dependency Injection is used.
In your case, you may prefer having a concrete converter that you inject into a class which needs a conversion of some values to hexadecimal. An interface, implemented by this concrete class, would define the contract required to convert the values.
Not only would you be able to test your code easier, but you'll also be able to swap implementations later (since there are lots of other possible ways of converting values to hexadecimal, some of them producing different outputs).
Exactly. And this is one of the problems with static methods, another one being that OOP is a much better alternative in most situations.
This is also one of the reasons Dependency Injection is used.
In your case, you may prefer having a concrete converter that you inject into a class which needs a conversion of some values to hexadecimal. An interface, implemented by this concrete class, would define the contract required to convert the values.
Not only would you be able to test your code easier, but you'll also be able to swap implementations later (since there are lots of other possible ways of converting values to hexadecimal, some of them producing different outputs).
answered 9 hours ago
Arseni MourzenkoArseni Mourzenko
116k26 gold badges293 silver badges462 bronze badges
116k26 gold badges293 silver badges462 bronze badges
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
@ArseniMourzenko so when injecting a calculator class implementing amultiplymethod, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying istoHexis very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.
– Steve Chamaillard
7 hours ago
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case wheretoHexis used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?
– Steve Chamaillard
6 hours ago
|
show 9 more comments
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
@ArseniMourzenko so when injecting a calculator class implementing amultiplymethod, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying istoHexis very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.
– Steve Chamaillard
7 hours ago
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case wheretoHexis used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?
– Steve Chamaillard
6 hours ago
1
1
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
How will that not make the code dependant on the success of the converter tests ? Injecting a class, an interface or anything you want does not make it magically work. If you were talking about side effects then yes there would be a ton of value injecting a fake instead of hard coding an implementation, but that problem never existed in the first place anyway.
– Steve Chamaillard
8 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
@steve when a unit fails do you want to see a sea of red in your test results, or just have the broken code show red?
– Ewan
7 hours ago
1
1
@ArseniMourzenko so when injecting a calculator class implementing a
multiply method, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying is toHex is very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.– Steve Chamaillard
7 hours ago
@ArseniMourzenko so when injecting a calculator class implementing a
multiply method, you'd mock this? Which means in order to refactor (and use the * operator instead), you'll have to change every single mock declaration in your code? Doesn't look like easy code to me. All I'm saying is toHex is very simple and has no side effects at all so I don't see any reason to mock or stub this. It's too much cost for absolutely no profit. Not saying we shouldn't inject it though, but that depends on usage.– Steve Chamaillard
7 hours ago
1
1
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
@steve surely this is exactly what arseni is saying. The static call is bad design, you want your unit tests to test specific parts of the code and static prevents this. Saying 'its a simple function that will never break' doesnt help you when it does break
– Ewan
7 hours ago
1
1
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case where
toHex is used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?– Steve Chamaillard
6 hours ago
@ArseniMourzenko I wasn't clear, I don't think having an interface is complex at all in this situation. I was saying that using mocks in these situations seem overkill and make tests harder to read, to write and to modify. When I say "doesn't look like easy code", I'm extrapolating to the case where
toHex is used everywhere and so if tested with mocking every time well for any change I'll have to change many tests, right?– Steve Chamaillard
6 hours ago
|
show 9 more comments
Thanks for contributing an answer to Software Engineering Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f393870%2fhow-to-unit-test-methods-which-using-static-methods%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
Then all tests of Foo.Do will depend on the success of TestToHex_works-- So? You don't have classes that depend on the success of other classes?– Robert Harvey♦
9 hours ago
2
I've never quite understood this obsession with free/static functions and their so-called non-testability. If a free function is free of side-effects, it is the easiest thing on the planet to test and prove it works. You've demonstrated this quite effectively in your own question. How do you test ordinary, side-effect free methods (that aren't dependent on class state) in object instances? I know you have some of those.
– Robert Harvey♦
9 hours ago
The only downside of this code using static functions is that you can’t easily use something else than
toHex(or swap implementations). Apart from that everything is fine. Your code converting to hex is tested, now there’s another code using that tested code as a utility to achieve its own goal.– Steve Chamaillard
8 hours ago
2
I am completely missing what is the problem here. If ToHex doesn't work, then it's clear that Do won't work either.
– Simon B
8 hours ago
2
The test for Foo.Do() shouldn't know or care that it calls ToHex() under the covers, that's an implementation detail.
– 17 of 26
7 hours ago