Unit testing consists of testing your code in complete isolation. When you have code that interacts with external resources (e.g., Location Services), you need to design seams into your architecture which will allow you to mock out that external code.
You mentioned testing code that could behave differently when GPS is enabled/disabled. This is a good example of where a seam could be introduced. For example, consider that you had the following code:
var watcher = new GeoCoordinateWatcher();
watcher.Start();
if (watcher.Permission.Equals(GeoPositionPermission.Granted))
{
// Do stuff that requires GPS
}
else
{
// Handle situation where GPS is disabled
}
You aren't able to test this code in isolation because it is tightly coupled to the Location Services (specifically, the GeoCoordinateWatcher
class). To address this, you can introduce an abstraction with the following interface:
public interface IGpsChecker
{
bool IsGpsEnabled();
}
Using this interface, your code could be changed to:
if (m_gps_checker.IsGpsEnabled()) // m_gps_checker is supplied to your class via constructor, etc.
{
// Do stuff that requires GPS
}
else
{
// Handle situation where GPS is disabled
}
In your production code, you would provide the class with an implementation that simply uses the original logic:
public class LocationServicesGpsChecker : IGpsChecker
{
public bool IsGpsEnabled()
{
var watcher = new GeoCoordinateWatcher();
watcher.Start();
return watcher.Permission.Equals(GeoPositionPermission.Granted);
}
}
However, in your test code you would provide a test double to the class that you're testing, giving you precise control of the conditions under which you're working.