I create a dll
for my application. I am using Facade design pattern
for encapsulate API who makes some programmers (not my organization) because they decision is uncomfortable.
Their API works like this:
- Initialize object of DiadocApi
- Auth for getting token
For initialize DiadocApi object I need developerKey
(get for a subscription).
For authorization I need login
, password
.
My decision badly because it's a singleton and I need make unit-tests. That can I change in my code?
//I GET IT FROM NUGET PACKAGE
using Diadoc.Api;
public sealed partial class DiadocApiFacade
{
private static readonly object _mutex = new object();
private static DiadocApiFacade _instance;
private string _token;
private DiadocApi _api;
private DiadocApiFacade() { }
public static string DefaultUrl => "url was here";
public string DefaultFromBoxId { get; set; }
public DiadocApi Api { get => _api; private set => _api = value; }
public static DiadocApiFacade GetInstance()
{
if (_instance == null)
{
lock (_mutex)
{
if (_instance == null)
{
_instance = new DiadocApiFacade();
}
}
}
return _instance;
}
public string Authenticate(string login, string password, string privateDeveloperKey)
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(developerKey))
throw new ArgumentNullException();
Api = new DiadocApi(developerKey, DefaultUrl, new WinApiCrypt());
return _token = _api.Authenticate(login, password);
}
//method for example, >60% methods like that
public Document GetDocument(string messageId, string documentId, string boxId = null)
{
return _api.GetDocument(_token, boxId ?? DefaultFromBoxId, messageId, documentId);
}
}
CodePudding user response:
I assume you want to make unit tests for your code that's consuming DiadocApiFacade
.
Dependency inversion to the rescue! Abstract your DiadocApiFacade
with an interface. Make use of the Factory Pattern to create the object. Below is a simple example but you can expand the factory if you need the facade to behave a certain way (like a settings class to change where it's connecting to).
GetOrCreate
Will return the same instance but if you're using a dependency injection framework in your project (there are many that might suite your needs), use that instead.
public interface IDiadocApiFacade
{
string Authenticate(string login, string password, string privateDeveloperKey);
public Document GetDocument(string messageId, string documentId, string boxId);
public Document GetDocument(string messageId, string documentId);
}
public class DiadocApiFacadeFactory
{
private static IDiadocApiFacade? _instance = null;
public IDiadocApiFacade Create() //Add parameters
{
return new DiadocApiFacade();
}
public IDiadocApiFacade GetOrCreate()
{
if(_instance == null)
_instance = Create();
return _instance;
}
}
public sealed partial class DiadocApiFacade : IDiadocApiFacade
{
internal DiadocApiFacade() { }
public string Authenticate(string login, string password, string privateDeveloperKey) => string.Empty;
public Document GetDocument(string messageId, string documentId)
=> GetDocument(messageId, documentId, null);
public Document GetDocument(string messageId, string documentId, string? boxId) => new Document();
}
Then you can just make use of [moq)[https://www.nuget.org/packages/moq/] for your unit testing and fake the implementation of IDiadocApiFacade