How do I create unit tests if the method or procedure I'm testing against relies on a piece of code from a 3rd party? Say, I have a method that uses classes from a third party source that requires setup that can only be done in a functional test. How should I approach this? Most of the time, the third party dependency can't be mocked, but my method really needs to make use of it.
Also, should I avoid my unit tests or even my functional tests from harnessing actual data? Like, should my tests never connect to a Database API to temporarily add data, operate and test against it, then delete it afterwards?
unit tests
you should tests everything. but not everything using unit-tests. unit tests don't depend on environment - database, internet connection etc. best practices for working with untrusted/unstable 3rd party tools is to create anti-corruption layer between your code and 3rd party code. so refactor your code to make your business logic as independent as possible. and unit-test the business logic.
if you're not sure how the 3rd party code works or if it change in the future, you can do 'learning tests'. these are unit-tests (if possible) that assert the behaviour you rely on. in learning tests you test only 3rd party code, not yours
if the 3rd party code is more-less trusted (well known open-source libraries) then you assume it works, don't do any separation and you unit-test only your code, not the libraries.
non-unit tests
if your tests require external environment (db, network etc) then you should do integration tests. its purpose is not to test business logic but rather that if you connected all the parts correctly. sql testing is one the most famous exceptions.
there is no simple rule how to do integration tests (you can write books about sql testing). it depends what exactly you want to test, how much similarity to your production environment you need/want. for example you may do sql testing against in-memory db or against your production-like db (oracle, postgres etc). however you design your integration tests you must assure that each test starts with know environment state. and you have take into consider errors that leaves environment in dirty state and speed of such tests
you said:
Most of the time, the third party dependency can't be mocked
Why? You can always define an interface for your interactions with the 3rd party component, then provide an implementation which simply delegates each call to the 3rd party component, then you are able to provide a mock of this interface for your tests.
this might be a lot of work if the 3rd party component has a large API, but it might still be worth doing.
Similar projects exist for creating wrappers around the .net filesystem classes so that you can write tests which do not rely on the filesystem.
So you could do something like this:
public interface IMyDependency
{
public void SomeMethod();
public int CaclateSomething();
//add other methods that you will call in the 3rd party dependency
}
Then have a wrapper which just delegates to the actual 3rd party component you are using, like this:
public class MyDependencyWrapper : IMyDependency
{
private My3rdPartyDepency actualDependency;
public MyDependencyWrapper(My3rdPartyDepency actualDependency)
{
this.actualDependency=actualDependency;
}
public void SomeMethod()
{
actualDependency.SomeMethod()l
}
public int CaclateSomething(string aParam)
{
return actualDependency.CalculateSomething(aParam);
}
//add other methods that you will call in the 3rd party dependency
}
now with this you can use just the interface in your tests, and so can write unit tests with no dependency on the actual 3rd party component.
Generally, it is assumed that 3rd party software is tested and that it works fine. Although it can surprise you when you discover a bug.
It depends what you are unit testing. Some things, like for example access to some exotic piece of hardware or resource, or simple a network connection, should not be unit tested. For such calls, we use mocks, and don't unit test them.
For databases, you can either use mocks, instead of real classes to access the database. Or, you can create database in memory in the unit test setup method, and destroy them in the cleanup.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With