In my view integration tests are the most important tests, because they are the ones which tell you if your application actually works when its all put together.
However, they have some downsides
- they require a running system with all dependencies to test against
- they are slow to run
- some tests are necessarily destructive and so cant be run against live environments.
- they tend to be 'top level' tests. they will tell you something is wrong but not what that thing is.
Unit tests don't have these downsides, you can quickly run hundreds of unit tests on a dev machine without deploying the whole app.
So don't skip unit tests just because you have an integration test and don't skip integration tests because you have unit tests.
One trick you can do to save some code is to make your tests work both as unit and integration by allowing them to mock or not mock dependencies depending on an input or setting.
This allows you to run your tests as unit tests quickly to verify the code. Then as integration to verify the setup and deployment.
Edit : example of how to combine integration and unit tests without code duplication.
public class AuthServiceTests
{
[TestCase("api.myapp.com/auth", "databaseuser", true, Category="Integration")]
[TestCase("mock", "mockuser", true, Category="Unit")]
public void IsUserTest(string target, string username, bool expected)
{
//SetUp
if(target != "mock")
{
httpClient = new HttpClient(target);
}
else
{
httpClient = new MockHttpClient();
}
var authService = new AuthService(httpClient);
var actual = authService.IsUser(user);
//obvs this might fail if the databases changes in the integration version
//or the db isnt setup right, or the connection string in the api is wrong etc
//the mock one will only fail if the code has a bug of some kind, say it doesnt work with long usernames, or emoticons or something
Assert.AreEqual(expected, actual);
}
}