I have the following method:
private string _google = @"http://www.google.com";
public ConnectionStatus CheckCommunicationLink()
{
//Test if we can get to Google (A happy website that should always be there).
Uri googleURI = new Uri(_google);
if (!IsUrlReachable(googleURI, mGoogleTest开发者_StackOverflowString))
{
//The internet is not reachable. No connection is available.
return ConnectionStatus.NotConnected;
}
return ConnectionStatus.Connected;
}
The question is, how do I get it to not try the connection to Google (thus avoiding the dependency on the internet being up).
The easiest way is to take _google
and change it to point to something local to the machine. But to do that I need to make _google
public
. I would rather not do that because _google
should not ever be changed by the app.
I could make `_google' a param to an overloaded version of the method (or object constructor). But that too exposes an interface that I don't ever want the app to use.
The other option is to make _google
internal
. But for the app, internal
is the same as public
. So, while others cannot see _google
, the app interface still exposes it.
Is there a better way? If so, please state it.
(Also, please don't pick on my example unless it really helps figure out a solution. I am asking for ideas on general scenarios like this, not necessarily this exact example.)
Refactor your code to depend on an ICommunicationChecker:
public interface ICommunicationChecker
{
ConnectionStatus GetConnectionStatus();
}
Then your test(s) can mock this interface making the implementation details irrelevant.
public class CommunicationChecker : ICommunicationChecker
{
private string _google = @"http://www.google.com";
public ConnectionStatus GetConnectionStatus()
{
//Test if we can get to Google (A happy website that should always be there).
Uri googleURI = new Uri(_google);
if (!IsUrlReachable(googleURI, mGoogleTestString))
{
//The internet is not reachable. No connection is available.
return ConnectionStatus.NotConnected;
}
return ConnectionStatus.Connected;
}
}
Why do you have _google hard coded in your code? Why not put it in a configuration file which you can then change for your test for example?
Some options:
- make
_google
load from an external configuration (maybe providing www.google.com as a default value) and supply a special configuration for unit tests; - place the unit test class inside the class containing the
CheckCommunicationLink
method.
Note: I would strongly recommend making it configurable. In real-world cases relying on the availability of a particular 3rd party web site is not a good idea, because they can be blocked by a local firewall etc.
For unit testing purposes you should mock whatever http connection you are using in your class (which is hidden in IsUrlReachable
method). This way you can check that your code is really trying to connect to google without actually connecting. Please paste the IsUrlReachable
method if you need more help with mocking.
If the above solution is not an option, you could consider having a local test http server and:
- Making the url configurable, so that you can point to the local address
- (this one is nasty) Use reflection to change _google before the tests
- (most purist will disagree here) You could create an overload taking the parameter and use this one for testing (so you test only
CheckCommunicationLink(string url)
method
code for (3):
private string _google = @"http://www.google.com";
public ConnectionStatus CheckCommunicationLink()
{
return CheckCommunicationLink(_google);
}
public ConnectionStatus CheckCommunicationLink(string url)
{
//Test if we can get to Google (A happy website that should always be there).
Uri googleURI = new Uri(url);
if (!IsUrlReachable(googleURI, mGoogleTestString))
{
//The internet is not reachable. No connection is available.
return ConnectionStatus.NotConnected;
}
return ConnectionStatus.Connected;
}
精彩评论