Writing unit tests for classes that depend on external libraries/sdks - c#

My code consists of the following components:
1 - IMyService: interface that defines properties/methods of the class that will implement it.
2 - MyService: concrete implementation of IMyService.
public interface IMyService
{
Task<MyResult> CreateAsync(string id, string json);
}
internal class MyService : IMyService
{
private readonly ExternalService _externalService;
public class MyService(ExternalService externalService)
{
this._externalService = externalService;
}
public async Task<MyResult> CreateAsync(string id, string json)
{
ServiceResult serviceResult = await this._externalService.RunAsync(id, json);
return new MyResult(serviceResult);
}
}
MyService class depends on third party library/SDK/package called ExternalService and implements method CreateAsync.
CreateAsync method takes 2 input parameters, invokes RunAsync method on ExternalService, receives result and creates my own class from result.
Question 1)
How would I approach unit testing CreateAsync method in MyService class? Is there any value in writing unit tests for it at all since it contains no logic?
Question 2)
ExternalService has its own Exceptions that it can throw when executing RunAsync method - should I capture exceptions thrown by RunAsync (wrapping try/catch around it) and cast them to my own Exception? For example - ExternalServiceException => MyServiceException.

Mock it with Moq and Autofixture. I don't know what unit testing framework you intend to use. So I would use Xunit as an example.
If it is calls to an external service you're only interested in testing what it can return.
First create an autofixture class. This is an attribute that is necessary for our test cases. More info here
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture()
.Customize(new AutoMoqCustomization()))
{
}
}
[Theory]
[AutoMoqData]
public async Task Validate_Service_ReturnResult([Frozen]Mock<IMyService> someService, ServiceResult mockResult, SomeClass sut){
//Set up interface to return what you want.
//In this case it returns mockResult always,
//but you can edit the properties of this to be whatever best fits your test case.
someService.Setup(x => x.CreateAsync(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(mockResult);
var result = await someService.Object.CreateAsync("ree", "skee");
//The class we are actually testing
var res =sut.DoSomething("someId", "someJson")
Assert.NotNull(res);
}
The [Frozen]-attribute makes sure that the behavior of the mocked someService is identical throughout all your code.
Doing all this is argueably a lot better than "faking" your interface for each testcase. Just imagine that you want CreateAsync to return different httpcodes like 404, 200, or 500. Have fun creating a new implementation of the interface for each case. With autofixture you just have set it up in the the beginning of your testcase.
The class we want to run our tests on
public class SomeClass{
IMyService someService;
public SomeClass(IMyservice someService){
this.someService = someService
}
public async Task<string> DoSomething(string id, string json){
var res = await this.someService.CreateAsync(id, json);
if(res.HttpStatusCode == 200){
//then do bla bla bla
...
}
}
Question 1: Yes. It is definitely worth it to unit test your services. You need to see if your code handles negative results. It would suck if this was a service that crashed because a result wasn't handled properly. For example if you expected an object from the service but receives null. Then before long you will have a null reference exception and a crashed service.
Question 2: Doesn't matter. Either way exceptions should be logged. If there is something important you want logged so you can query it easily eg. HttpCode. Then please do. It depends on two things. First: Can you handle the exceptions? And second: Do you log your exceptions to some central database?

Related

Unit testing Reactive code in constructors using AutoMock from AutoFixture?

I'm hitting a bit of a chicken and egg problem setting up my mocks for Reactive Extensions code in a constructor. Here's the class under test (along with the service interface it depends on):
class MyViewModel
{
public int Thing { get; set; }
public MyViewModel(IMyService service)
{
service.StreamOfThings.Subscribe(x => Thing = x));
}
public void SomeClickEvent()
{
// Do something with `Thing`
}
}
public interface IMyService
{
IObservable<int> StreamOfThings { get; }
}
To make testing easier, I have also defined a custom attribute named AutoMockData I can use to use Moq to inject mock instances into my classes through AutoFixture:
public class AutoMockDataAttribute : AutoDataAttribute
{
private static IFixture Create() =>
new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
public AutoMockDataAttribute() : base(Create) {}
}
With this, I am ready to write my test (using NUnit3):
[Test, AutoMockData]
public void Verify_some_behavior(
[Frozen] Mock<IMyService> mockService,
MyViewModel vm)
{
mockService.Setup(x => x.StreamOfThings).Returns(Observable.Return(100));
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
This test fails. I believe this fails because the constructor of MyViewModel sets up an observable pipeline on a different instance of IObservable than the one I set up in the unit test method.
The ideal solution here would be to use the IObservable<> instance that was set up using AutoFixture, but I'm not sure how to best do that. It would somehow need to already set up a pre-constructed pipeline for me.
The workaround I have found is to not use the AutoMock functionality of AutoFixture and instead construct a Fixture directly and directly use the .Freeze() and .Create() methods in the proper order. However, this leads to an arguably more difficult to read and less clean unit test body.
How can I continue to implement my test as shown here but also be able to set up any observables before they are used in the SUT's constructor?
I think the issue here is that you never actually exercise the observable, so Thing keeps the value that AutoFixture assigned it on creation.
In the example below the Subject is frozen as an IObservable<int> which is then resolved as the return value for the StreamOfThings. Then the subject is forced to trigger the subscribers.
[Test, AutoMockData]
public void Verify_some_behavior(
[Frozen(Matching.ImplementedInterfaces)] Subject<int> observable,
MyViewModel vm)
{
observable.OnNext(100);
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
The example is equivalent to the following:
[Test, AutoMockData]
public void Verify_some_behavior(
Subject<int> observable,
[Frozen] Mock<IMyService> mockService,
MyViewModel vm)
{
mockService.Setup(x => x.StreamOfThings).Returns(observable);
observable.OnNext(100);
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
This way of writing the test should also make it obvious how to handle multiple observable properties.

C# Generic method calling two different services

I have the following method, which is to add product using the injected service! It is called inside a static calls hence it is static!
public static async Task AddNewProducts(Guid shopId)
{
var productAService = IoC.Services.GetService<IProductAService>();
var added = await productAService.AddProduct(shopId);
}
It works fine but I need to make it generic so that I can use different services with it.
Something like this!
public static async Task AddNewProducts<T>(Guid shopId)
where T : IProductAService, IProductBService
{
var productService = IoC.Services.GetService<T>();
var added = await productService.AddProduct(shopId);
}
However the second methods complains that the AddProduct method is ambiguous, not sure how I can make sure it is calling the right method from the related service!
Your 2 services need a common interface
public interface IProductService
{
void AddProduct(Guid shopId);
}
public interface IProductAService : IProductService
{
//specifics to service A
}
public interface IProductBService : IProductService
{
//specifics to service B
}
Then your static, generic method just constrains to the shared interface
public static async Task AddNewProducts<TProductService>(Guid shopId)
where TProductService : IProductService
{
var productService = IoC.Services.GetService<TProductService>();
await productService.AddProduct(shopId);
}
This gets slippery very quickly. You hinted that AddProduct is not a void, but returns a particular object. That's fine, you can make IProductService itself generic
public interface IProductService<TProduct>
{
TProduct AddProduct(Guid shopId);
}
public interface IProductAService : IProductService<ProductA>
{
//specifics to service A
}
public interface IProductBService : IProductService<ProductB>
{
//specifics to service B
}
But now you need to also pass the product type to the generic method, as I said - it gets slippery quickly (but maybe it'll do!)
public static async Task AddNewProducts<TProductService, TProduct>(Guid shopId)
where TProductService : IProductService<TProduct>
{
var productService = IoC.Services.GetService<TProductService<TProduct>>();
var added = await productService.AddProduct(shopId);
// Note "added" is of type TProduct
}
I call this situation "Generic hell". You are better of rethinking your design!
public static async Task AddNewProducts<T>(Guid shopId) where T : IProductAService, IProductBService
The problem with that line is that you're requiring T to implement both interfaces at once, not just one of them. You haven't even gotten to the errors that will spring up when you try to call this function, because presumably your class won't implement both.
Which leads me to question why you think you need to constrain your T like this. The only usage of T is to call Services.GetService<T>(), so the only constraint on it should be exactly the constraints that function requires, which are definitely not your two interfaces.

nsubstitute giving exception while creating substitute

We are Trying to integrate Nunit testing within our web application. here we are using Nsubstitute as a mocking framework.
The project architecture goes as below:
Public class BaseService : Glass.Mapper.Sc.SitecoreContext
{
public BaseService(){}
}
Public class DerivedService : BaseService
{
IGenericRepository<Item> _genericRepository;
public DerivedService ( IGenericRepository<Item> _repository)
{
_genericRepository= _repository;
}
public string DoSomethig(){}
}
Now to test the DoSomething() method of my DerivedService class i am creating the substitue of my repository and faking its response. which should let me test my service code.
[Test]
public void TestDoSomethigMethod()
{
var repository = Substitute.For<IGenericRepository<Item>>();
DerivedService tempService = new DerivedService(repository);
// Throws an exception of type System.Collections.Generic.KeyNotFoundException : The given key was not present in the dictionary. at base service constructor.
var response = tempService.DoSomething();
}
When i try to invoke the instance of derived service it throws me the exception at baseService constructor saying (The given key was not present in the dictionary)
we are using windsor castle for dependency injection & the Base Class inherits from Glass Mapper sitecore context class.
Please let me know if anyone faced any such problem or have a solution for this.
edit: code for test case updated as suggested by Pavel & Marcio.
NSubstitute will proxy public and virtual methods/properties only. You should either substitute interfaces or make sure the classes you substitute expose public virtual methods. As far as I can tell, yours are not virtual and while NSubstitute can create the object, it can't effectively proxy/mock anything on it.
Also, if your constructor is not parameter-less make sure you are providing a substitute (or a real instance) for every argument when substituting.
More details here: http://nsubstitute.github.io/help/creating-a-substitute/
You should not create a substitute for DerivedService, but for IGenericRepository<Item> and inject it into DerivedService.
You'll only create substitutes for the parts you want to mock, not the ones you want to test.
Here's what you should do:
[Test]
public void TestDoSomethigMethod()
{
var repository = Substitute.For<IGenericRepository<Item>>();
// Here you set up repository expectations
DerivedService tempService = new DerivedService(repository);
var response = tempService.DoSomething();
// Here you assert the response
}

How to unit test delegate was received in base class method?

I currently have a base service class that all my services extend. This is what one of the methods look like:
protected internal virtual T PerformServiceOperationWithExceptionHandling<T>(Func<T> func)
{
try
{
return func.Invoke();
}
...
}
In the derived classes I call the method like this:
public AddGuestResponse AddGuest(AddGuestRequest addGuestRequest)
{
return PerformServiceOperationWithExceptionHandling(() => AddGuestLogic(addGuestRequest));
}
I want to test AddGuest and ensure "AddGuestLogic" is being passed as a parameter in the base method? How do I achieve this with nSubstitute and nUnit. I don't think its possible?
================================================
I ended up using the following code:
[Test]
public void AddGuest_WhenCalled_PerformsAddGuestLogicWithExceptionHandling()
{
Func<AddGuestResponse> addGuestLogic = null;
_guestService.PerformServiceOperationWithExceptionHandling(Arg.Do<Func<AddGuestResponse>>(arg => addGuestLogic = arg));
var addGuestRequest = new AddGuestRequest();
_guestService.AddGuest(addGuestRequest);
_guestService.ClearReceivedCalls();
addGuestLogic.Invoke();
_guestService.Received().AddGuestLogic(addGuestRequest);
}
The _guestService is created in my setup method as follows: Substitute.ForPartsOf();
I second Sunny Milenov's answer, but would go one step further by advising you to change your design. I have learned the hard way that many of these headaches with testing base class behavior go away when you follow the principle of composition over inheritance.
I.e., if you refactor your base class to a collaborator, which you inject into your services' constructor, you can test that in isolation and mock it in your services' tests. No worrying about testing an abstract base class or testing the same exception handling in all of your services' tests.
You would test that the collaborator correctly invokes the func in the collaborator's tests.
In the services' tests you can just mock the collaborator to return the Func's result right away:
[Test]
public void ServiceLogicIsExecuted()
{
var collaborator = Substitute.For<ICollaborator>();
//Tell the test double to return the Func's result. You'd probably want to do this in the setup method.
collaborator.PerformServiceOperation(Arg.Any<Func<int>>()).Returns(x => ((Func<int>)x[0]).Invoke());
var sut = new Service(collaborator);
var result = sut.CalculateSomething();
Assert.That(result, Is.EqualTo(99));
}
public class Service
{
private readonly ICollaborator _collaborator;
public Service(ICollaborator collaborator)
{
_collaborator = collaborator;
}
public int CalculateSomething()
{
return _collaborator.PerformServiceOperation(ExecuteLogic);
}
private static int ExecuteLogic()
{
return 99;
}
}
public interface ICollaborator
{
T PerformServiceOperation<T>(Func<T> func);
}
Short answer - you shouldn't. Unit testing is about testing the behavior of the tested method, not the implementation details.
Long answer:
It doesn't matter how the class internally works, as far as it produces the expected results.
You need to test your public method on the final class and see if this works as expected. Testing a base/abstract class in isolation proves nothing.

What is the purpose of unit testing an interface repository

I am unit testing an ICustomerRepository interface used for retrieving objects of type Customer.
As a unit test what value am I gaining by testing the ICustomerRepository in this manner?
Under what conditions would the below test fail?
For tests of this nature is it advisable to do tests that I know should fail? i.e. look for id 4 when I know I've only placed 5 in the repository
I am probably missing something obvious but it seems the integration tests of the class that implements ICustomerRepository will be of more value.
[TestClass]
public class CustomerTests : TestClassBase
{
private Customer SetUpCustomerForRepository()
{
return new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[]
{
new Login { LoginCustId = 5, LoginName = "tdude" },
new Login { LoginCustId = 5, LoginName = "tdude2" }
}
};
}
[TestMethod]
public void CanGetCustomerById()
{
// arrange
var customer = SetUpCustomerForRepository();
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetById(5)).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetById(5));
}
}
Test Base Class
public class TestClassBase
{
protected T Stub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
}
ICustomerRepository and IRepository
public interface ICustomerRepository : IRepository<Customer>
{
IList<Customer> FindCustomers(string q);
Customer GetCustomerByDifID(string difId);
Customer GetCustomerByLogin(string loginName);
}
public interface IRepository<T>
{
void Save(T entity);
void Save(List<T> entity);
bool Save(T entity, out string message);
void Delete(T entity);
T GetById(int id);
ICollection<T> FindAll();
}
I may be missing something but it seems like every single aspect of your test is mocked up?
Generally speaking you only mock up the objects that aren't core to the test. In this case you may use this repository as the source for a function which you expect to do something with the repository to retrieve customer #5 and perform an operation on it.
For example you may mock up a customer repository so that you can call a method that verifies the login of a user. You'd use your mock repository to prevent your unit-test from relying on a real data-source, not to test your mock repository.
Rule #1 of testing:
Know what the purpose of your test is and what it is trying to prove before you write it. If you don't know what it proves, then it's useless :)
As the other posters have correctly said, you're stubbing an interface and then calling the stub -- this doesn't prove anything about whether your production code works.
What is a stub?
Stubs are used to provide canned values to drive some aspect of the class under test. E.g. Say you have a CustomerService that has an instance of type ICustomerRepository. If you wanted to see that the CustomerService could gracefully handle an error case when the repository was empty, you would stub the ICustomerRepository's GetCustomerById method to return nothing/null/throw an exception, then ensure that the CustomerService method did the correct thing (e.g. return a customer not found result).
I.e. the stub is just a collaborator that helps you reach the particular condition/behaviour of interest. We're testing CustomerService and the stubbed ICustomerRepository merely helps us achieve our goal.
You're not the first to ask this very question :). I usually advise developers to hand-roll their test doubles at first. It helps to understand all of the interactions and what the framework is actually doing for you.
Interfaces, by definition, are just contracts, so there's no code to test. You want to write unit tests against the concrete implementation(s) of the interface, because that is where the actual execution code lives.
If there's no concrete implementation of the interface and you're just mocking a concrete implementation, then your unit test is just based on a mock. That isn't really of much value.
Your test makes no sense to me. You are testing if a preprogrammed stub is returning the values you feed it, You are not testing any real code.
Follow dcp's reply. An interface is a declaration of methods. You should test implementations of these.

Categories

Resources