Mocking a class with internal SDK calls using NSubstitute - xunit

First time trying to use NSubstitute.
I have the following method in my Web API.
For those who don't know Couchbase, lets say that a collection/bucket is like a DB table and a key is like a DB row.
Couchbase_internal.Collection_GET returns Task<ICouchbaseCollection>
I would like to write 2 unit tests.
One that tests the returned class when the key exist and one when it doesn't (couchbaseServiceResultClass).
I don't really understand where is the part where I control whether or not the key exist in the mocked data.
public class CouchbaseAPI : ControllerBase, ICouchbaseAPI
{
// GET /document_GET?bucketName=<bucketName>&key=<key>
[HttpGet]
[Consumes("application/x-www-form-urlencoded")]
[Produces(MediaTypeNames.Application.Json)]
public async Task<couchbaseServiceResultClass> document_GET([FromQuery, BindRequired] string bucketName, [FromQuery, BindRequired] string key)
{
var collection = await Couchbase_internal.Collection_GET(bucketName);
if (collection != null)
{
IGetResult result;
try
{
// get document
result = await collection.GetAsync(key);
}
catch (CouchbaseException ex)
{
return new ErrorHandling().handleCouchbaseException(ex);
}
couchbaseServiceResultClass decryptResult = new();
try
{
// decrypt document
decryptResult = Encryption.decryptContent(result);
}
catch (Exception ex)
{
return new ErrorHandling().handleException(ex, null);
}
// remove document if decryption failed
if (!decryptResult.DecryptSuccess)
{
try
{
await collection.RemoveAsync(key);
}
catch (CouchbaseException ex)
{
return new ErrorHandling().handleCouchbaseException(ex);
}
}
decryptResult.Message = "key retrieved successfully";
// return result
return decryptResult;
}
else
{
return new ErrorHandling().handleError("Collection / bucket was not found.");
}
}
This is what I have so far for the first test:
public class CouchbaseAPITests
{
private readonly CouchbaseAPI.Controllers.ICouchbaseAPI myClass = Substitute.For<CouchbaseAPI.Controllers.ICouchbaseAPI>();
[Fact]
public async Task document_GET_aKeyIsRetrievedSuccessfully()
{
// Arrange
string bucketName = "myBucket";
string keyName = "myKey";
couchbaseServiceResultClass resultClass = new();
resultClass.Success = true;
resultClass.Message = "key retrieved successfully";
myClass.document_GET(bucketName, keyName).Returns(resultClass);
// Act
var document = await myClass.document_GET(bucketName, keyName);
// Assert
Assert.True(document.Success);
Assert.Equal("key retrieved successfully", document.Message);
}
}

If we want to test that we are retrieving documents from the Couchbase API properly, then generally we want to use a real instance (local test setup) of that API where possible. If we are mocking this then our tests are not really telling us about whether our code is working correctly (just that our mock is working the way we want it to).
When certain APIs are difficult to use real instances for (e.g. non-deterministic code, difficult to reproduce conditions such as network errors, slow dependencies, etc), that's when it can be useful to introduce an interface for that dependency and to mock that for our test.
Here's a very rough example that doesn't quite match the code snippets posted, but hopefully will give you some ideas on how to proceed.
public interface IDataAdapter {
IEnumerable<IGetResult> Get(string key);
}
public class CouchbaseAdapter : IDataAdapter {
/* Implement interface for Couchbase */
}
public class AppApi {
private IDataAdapter data;
public AppApi(IDataAdapter data) {
this.data = data;
}
public SomeResult Lookup(string key) {
try {
var result = data.Get(key);
return Transform(Decrypt(result));
} catch (Exception ex) { /* error handling */ }
}
}
[Fact]
public void TestWhenKeyExists() {
var testAdapter = Substitute.For<IDataAdapter>();
var api = new AppApi(testAdapter);
testAdapter.Get("abc").Returns(/* some valid data */);
var result = api.Lookup("abc");
/* assert that result is decrypted/transformed as expected */
Assert.Equal(expectedResult, result);
}
[Fact]
public void TestWhenKeyDoesNotExist() {
var testAdapter = Substitute.For<IDataAdapter>();
var api = new AppApi(testAdapter);
var emptyData = new List<IGetResult>();
testAdapter.Get("abc").Returns(emptyData);
var result = api.Lookup("abc");
/* assert that result has handled error as expected */
Assert.Equal(expectedError, result);
}
Here we've introduced a IDataAdapter type that our class uses to abstract the details of which implementation we are using to get data. Our real code can use the CouchbaseAdapter implementation, but our tests can use a mocked version instead. For our tests, we can simulate what happens when the data adapter throws errors or returns specific information.
Note that we're only testing AppApi here -- we are not testing the CouchbaseAdapter implementation, only that AppApi will respond in a certain way if its IDataAdapter has certain behaviour. To test our CouchbaseAdapter we will want to use a real instance, but we don't have to worry about those details for testing our AppApi transformation and decryption code.

Related

Spring unit tests [webflux, cloud]

I am new to the topic of unit testing and my question is whether I should perform the test as such of each line of code of a method or in what ways I can perform these tests to have a good coverage, if also, should exceptions be evaluated or not?
If for example I have this service method that also uses some helpers that communicate with other microservices, someone could give me examples of how to perform, thank you very much.
public Mono<BankAccountDto> save(BankAccountDto bankAccount) {
var count = findAccountsByCustomerId(bankAccount.getCustomerId()).count();
var customerDto = webClientCustomer
.findCustomerById(bankAccount.getCustomerId());
var accountType = bankAccount.getAccountType();
return customerDto
.zipWith(count)
.flatMap(tuple -> {
final CustomerDto custDto = tuple.getT1();
final long sizeAccounts = tuple.getT2();
final var customerType = custDto.getCustomerType();
if (webClientCustomer.isCustomerAuthorized(customerType, accountType, sizeAccounts)) {
return saveBankAccountAndRole(bankAccount);
}
return Mono.error(new Exception("....."));
});
}
EDIT
public Mono<BankAccountDto> save(BankAccountDto bankAccount) {
var count = findAccountsByCustomerId(bankAccount.getCustomerId()).count();
var customerDto = webClientCustomer
.findCustomerById(bankAccount.getCustomerId());
return customerDto
.zipWith(count)
.flatMap(tuple -> {
final var customDto = tuple.getT1();
final var sizeAccounts = tuple.getT2();
final var accountType = bankAccount.getAccountType();
// EDITED
return webClientCustomer.isCustomerAuthorized(customDto, accountType, sizeAccounts)
.flatMap(isAuthorized -> {
if (Boolean.TRUE.equals(isAuthorized)) {
return saveBankAccountAndRole(bankAccount);
}
return Mono.error(new Exception("No tiene permisos para registrar una cuenta bancaria"));
});
});
}
Given that you want to unit test this code, you would need to mock dependencies such as webClientCustomer.
Then you should always test whatever are the relevant paths within the code. Looking at your code I only see three relevant ones to be tested:
the method returns an empty Mono if webClientCustomer.findCustomerById(bankAccount.getCustomerId()); returns an empty Mono;
saveBankAccountAndRole(bankAccount) is called and your save() method actually returns whatever saveBankAccountAndRole(bankAccount) returns. This would should happen if webClientCustomer.isCustomerAuthorized(customerType, accountType, sizeAccounts) is true;
the method returns an exception if webClientCustomer.isCustomerAuthorized(customerType, accountType, sizeAccounts) is false.

Xamarin Form - Can't get return value data from Service class method into MainPage method for filtering

I'm new to Xamarin, I have an app in Xamarin-Form that it's fetching data from web api and getting user input from Entry control.
The web api service class is working fine and reaches the deserialization in the getCourses method as seen below in Code Snippet 1.
The Entry control as well is working fine until it retrieves the user input on the MainPage class, OnOkGetCourseButton method as seen below Code Snippet 2.
What I want to achieve is, inside MainPage.xaml.cs, I create a method that takes the user input data and check agaisnt the deseriaized json data (the Id specially),
if it finds the Id in deserialized List of data, then it can send the found data to another ViewPage and display them.
if It cannot find the data, it shows a dialog box.
So far, I tried to call Task<ObservableCollection> getCourses() method from the MainPage class, inside CheckCourseComplete as seen below but it giving me no value/nothing, some kind of null value.
I don't want to filter the user input against web api json response inside getCourses(),
I want to do that in a separate method to follow S-OLID (Single Responsibility Principle).
If it's not possible in a separate method, then I just need to get it worked.
Please what is the best way to achieve it?
Code Snippet 1
public class CourseService : ICourseService
{
string Base_Url = "https://www.test.com/api/TheCourse";
public async Task<ObservableCollection<Course>> getCourses()
{
try
{
string url = Base_Url;
HttpClient client = new HttpClient();
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await responseMessage.Content.ReadAsStringAsync();
var deserializedClass = JsonConvert.DeserializeObject<ObservableCollection<Course>>(result);
// I don't want to do that here, as it will violate SRP (SOLID)
return deserializedClass;
}
return null;
}
catch (Exception)
{
throw;
}
}
}
Code Snippet 2
namespace CourseMobile
{
public partial class MainPage : ContentPage
{
private string _getEntryText;
private readonly CourseViewModel orderViewModel;
public Course FetchCourse { get; set; }
public MainPage()
{
InitializeComponent();
CheckCourseComplete();
BindingContext = new CourseViewModel();
}
public string GetEntryText
{
get => _getEntryText;
set => _getEntryText = value;
}
public async void OnOkGetCourseButton(object sender, EventArgs e)
{
var inputtedCourseNumber = this.GetEntryText;
if(inputtedCourseNumber == string.Empty)
{
await DisplayAlert("", "Please enter your Course number", "OK 3");
}
else
{
CheckCourseComplete();
this.GetEntryText = inputtedCourseNumber;
await DisplayAlert("New Text", inputtedCourseNumber, "OK 2");
}
}
void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
var newText = e.NewTextValue;
this.GetEntryText = newText;
}
public async void CheckCourseComplete()
{
CourseService myCourse = new CourseService();
await myCourse.getCourses(); // It doesn't return the json data (web api data)
// I need to check user input + (web api data) here
}
}
}
getCourses is async, so you need to use await when calling it
public async void CheckCourseComplete()
{
CourseService myCourse = new CourseService();
var data = await myCourse.getCourses();
// now filter data
}

JavaFX: How to trigger TreeItem event

I have class myClass extends TreeItem<file> to be used as datamodel in a TreeTableView mostly following the example here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeItem.html .
public class myTreeItem extends TreeItem<File>
private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
#Override public ObservableList<TreeItem<File>> getChildren() {
// ... full code see link to Oracle documentation
return super.getChildren();
}
private ObservableList<TreeItem<File>> buildChildren(TreeItem<File> TreeItem) {
// ... full code see link to Oracle documentation
};
}
I have added a function to add children to this item. I have problems with the correct update of the TreeTableView. More details see in the code and comments below:
public void addChild(String name) {
itemManger.addChild(this.getValue(), name); // Generate Child
isFirstTimeChildren = true; // Ensure that buildChildren() is called, when getchildren() is called.
// getChildren(); // If I would activate this line,
// all listeners would be notified
// and the TreeTableView is updated.
// This is most likely due to the call super.getChildren();
// However I want to throw the event on my own in order
// to avoid the extra call of this.getChildren(). Here is my
// (not sufficent) try:
EventType<TreeItem.TreeModificationEvent<MLDCostumizableItem>> eventType = TreeItem.treeNotificationEvent();
TreeModificationEvent<MLDCostumizableItem> event = new TreeModificationEvent<>(eventType,this);
Event.fireEvent(this, event);
// Here I don't know how to get a value for target.
// Is there some standard target, which includes all FX components?
}
How the correctly throw this event?
Seems that I had a missunderstanding in how the triggering works in JavaFX. Now the most simple solution is:
#Override // Taken from Link
public void update(Observable observ, Object arg1) {
if (observ!=this.item)
{
LOGGER.error(new MLDConnectionException("Unexpected call of update() with observ = " + observ.toString()));
return;
}
// Build new Chidren list
try {
super.getChildren().removeIf((x) -> true); // empty list
super.getChildren().setAll(buildChildren(this));
} catch (MLDConnectionException e) {
LOGGER.error("Error when genereting children List: ", e);
}
}
public File addChild(String name) throws MLDException {
File newChild = itemManger.addChild(item, name);
update(this.item, null);
return newChild;
}

Xamarin Realm - when to close Realm

I have a Shared Project where I have changed the database to Realm instead of SQLite.
My problem is, if I close the Realm in my DatabaseManager, the result is removed. Therefore i have created a static singelton instance of the Realm, which all my DatabaseManager use. Now my app crash after short time on memory, and if i remove all my database-functions, it works.
I create my Realm-instance here:
public class RealmDatabase
{
private Realm mRealmDB;
public Realm RealmDB
{
get
{
if (mRealmDB == null || mRealmDB.IsClosed)
{
SetRealm ();
}
return mRealmDB;
}
}
static RealmDatabase cCurrentInstance;
public static RealmDatabase Current
{
get
{
if (cCurrentInstance == null)
cCurrentInstance = new RealmDatabase ();
return cCurrentInstance;
}
}
public RealmDatabase ()
{
}
private void SetRealm ()
{
var config = new RealmConfiguration ("DBName.realm", true);
mRealmDB = Realm.GetInstance (config);
}
public Transaction BeginTransaction ()
{
return RealmDB.BeginWrite ();
}
}
The I have my DatabaseManagler looking like this:
public class NewFreeUserManager
{
internal Realm RealmDB = RealmDatabase.Current.RealmDB;
static NewFreeUserManager cCurrentInstance;
public static NewFreeUserManager Current
{
get
{
if (cCurrentInstance == null)
cCurrentInstance = new NewFreeUserManager ();
return cCurrentInstance;
}
}
private NewFreeUserManager ()
{
}
internal bool Save (FreeUser freeuser)
{
try
{
using (var trans = RealmDB.BeginWrite ())
{
RealmDB.RemoveAll<FreeUser> ();
var fu = RealmDB.CreateObject<FreeUser> ();
fu = freeuser;
trans.Commit ();
}
return true;
}
catch (Exception e)
{
Console.WriteLine ("FreeUser save: " + e.ToString ());
return false;
}
}
internal FreeUser Get ()
{
return RealmDB.All<FreeUser> ().FirstOrDefault ();
}
}
Can anyone help me?
there are a few issues with your current setup that prevent you from persisting objects properly.
The first and very important one is that Realm instances are not thread-safe. That is, using them as singletons is strongly discouraged, unless you are certain that you'll never access them from another thread.
The second is more subtle, but in your save method you are calling:
var fu = RealmDB.CreateObject<FreeUser>();
fu = freeuser;
What it does is, effectively, you are creating an object in the Realm, and then assigning the variable to another object. This will not assign freeuser's properties to fu, it just replaces one reference with another. What you're looking for is Realm.Manage so your code should look like this:
using (var trans = RealmDB.BeginWrite())
{
RealmDB.Manage(freeuser);
trans.Commit();
}
Once you fix the second bug, you should be able to go back and close Realm instances when you don't need them anymore.

Web API error response Id

I have an error response model in my API project:
public class ErrorResponse
{
public string ErrorId { get; set;}
public string Message {get; set;}
}
I need to generate a random ErrorId. I saw the use of Random class but just wondering what is the best way to do this. Some consideration, do I need to create the ErrorId in the constructor of ErrorResponse class and make ErrorId as read-only (no setter) or do I let the ErrorId set by the calling class.
You can create a new Guid and assign it to ErrorId in the constructor:
public ErrorResponse()
{
ErrorId = Guid.NewGuid().ToString();
}
Alternatively, you may want to give the client an http response and include the ErrorId:
return Content(HttpStatusCode.BadRequest, "ErrorId");
You can use the Random class or generate a Guid. But I just want to expand on what I think you are trying to do. Instead of your own custom error response - perhaps considering using the HttpResponseException or the HttpResponseMesssage. You can include a custom / random error identifier in Content / reason or in the message.
public IEnumerable<string> Get()
{
try
{
SomeMethod();
return new string[] { "xxx", "yyy" };
}
catch (Exception e)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An error occurred."),
ReasonPhrase = "your custom error id"
});
// log
}
}
And:
public HttpResponseMessage Get(int id)
{
try
{
// your code
}
catch (Exception ex)
{
// Log exception code goes here
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "your custom error id.”);
}
}
Best way to create Random number is to use Random class in C#... Here is the example
Random rnd = new Random();
int first = rnd.Next(1, 40); //Number between 1(inclusive) and 40(exclusive)
int second = rnd.Next(10); //Number between 0 and 9
Note: If you are going to create more than one random numbers then you should use the same instance of the Random class. If you create new instance too close in time, there are chances that they both will produce the same random numbers as Random class is based(seeded)on System clock.
I use Random but quite not sure if there are consequences in an API application(due to thread-safety, etc). So in the constructor, I generate the ErrorId.
public ErrorResponse()
{
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.!+-?";
ErrorId = new string(Enumerable.Repeat(chars, 10)
.Select(s => s[random.Next(s.Length)]).ToArray());
}

Resources