Is there a way to have a ArC CDI-Container in Unit-Tests without using the full force of #QuarkusTest, analogous to weld-junit for weld? I'd rather not start up my whole application for a unit-test, but sometimes I need a CDI container, say if I want to test Interceptors and Decorators. Given that ArC is (intentionally) not fully compatible to the CDI spec, I'd rather test against the CDI container that will also be used in production than against weld.
Related
I'm writing a Gradle plugin that interacts with an external HTTP API. This interaction is handled by a single class (let's call it ApiClient). I'm writing some high-level tests that use Gradle TestKit to simulate an entire build that uses the plugin, but I obviously don't want them to actually hit the API. Instead, I'd like to mock ApiClient and check that its methods have been called with the appropriate arguments, but I'm not sure how to actually inject the mocked version into the plugin. The plugin is instantiated somewhere deep within Gradle, and gets applied to the project being executed using its void apply(Project project) method, so there doesn't appear to be a way to inject a MockApiClient object.
Perhaps one way is to manually instantiate a Project, apply() the plugin to it (at which point, I can inject the mocked object because I have control over plugin instantiation), and then programmatically execute a task on the project, but how can I do that? I've read the Gradle API documentation and haven't seen an obvious way.
A worst-case solution will be to pass in a debug flag through the plugin extension configuration, which the plugin will then use to determine whether it should use the real ApiClient or a mock (which would print some easily grep-able messages to the STDOUT). This isn't ideal, though, since it's more fuzzy than checking the arguments actually passed to the ApiClient methods.
Perhaps you could split your plugin into a few different plugins
my-plugin-common - All the common stuff
my-plugin-real-services - Adds the "real" services to the model (eg RealApiClient)
my-plugin-mock-services - Adds "mock" services to the model (eg MockApiClient)
my-plugin - Applies my-plugin-real-services and my-plugin-common
my-plugin-mock - Applies my-plugin-mock-services and my-plugin-common
In the real world, people will only ever apply: 'my-plugin'
For testing you could apply: 'my-plugin-mock'
Let's say that we have a class Controller that depends on a class Service, and the Service class depends on a class Repository. Only Repository communicates with an external system (say DB) and I know it should be mocked when unit testing is executed.
My question: For unit tests, should I mock the Service class when Controller class is tested even though the Service class doesn't depend on any external systems directly? and Why?
It depends on the kind of test you are writing: integration test or unit test.
I assume you want to write a unit test in this case. The purpose of a unit test is to solely test the business logic of your class so every other dependency should be mocked.
In this case you will mock the Service class. Doing so also allows you to prepare for testing certain scenarios based on the input you are passing to a certain method of Service. Imagine you have a Person findPerson(Long personID)-method in your Service. When testing your Controller you are not interested in doing everything that's necessary for having Service actually return the right output. For a certain test scenario for your Controller you just want it to return a Person whereas for a different test scenario you don't want it to return anything. Mocking makes this very easy.
Also note that if you mock your Service you don't have to mock Repository since your Service is already a mock.
TLDR; When writing a unit test for a certain class, just mock every other dependency to be able to manipulate the output of method invocations made to these dependencies.
Yes, mock Services when testing controllers. Unit tests help to identify the location of a regression. So a Test for a Service code should only fail if the service code has changed, not if the controller code has changed. That way, when the service test fails, you know for sure that the root cause lies in a change to Service.
Also, usually it is much easier to mock the service than to mock all repositories invoked by the service just to test the controller. So it makes your tests easier to maintain.
But in general, you may keep certain util classes unmocked, as you loose more than you gain by mocking those. Also see:
https://softwareengineering.stackexchange.com/questions/148049/how-to-deal-with-static-utility-classes-when-designing-for-testability
As with all engineering questions, TDD is no different. The answer always is, "it depends". There's always trade offs.
In the case of TDD, you develop the test through behavioral expectations first. In my experiences, a behavioral expectation is a unit.
An example, say you want to get all users that start with the last name 'A', and they are active in the system. So you would write a test to create a controller action to get active users that start with 'A' public ActionResult GetAllActiveUsersThatStartWithA().
In the end, I might have something like this:
public ActionResultGetAllActiveUsersThatStartWithA()
{
var users = _repository.GetAllUsers();
var activeUsersThatStartWithA = users.Where(u => u.IsActive && u.Name.StartsWith('A');
return View(activeUsersThatStartWithA);
}
This to me is a unit. I can then now refactor (change me implementation without changing behavior by adding a service class with the method below)
public IEnumerable<User> GetActiveUsersThatStartWithLetter(char startWith)
{
var users = _repository.GetAllUsers();
var activeUsersThatStartWithA = users.Where(u => u.IsActive && u.Name.StartsWith(startsWith);
}
And my new implementation of the controller becomes
public ActionResultGetAllActiveUsersThatStartWithA()
{
return View(_service.GetActiveUsersThatStartWithLetter('A');
}
This is obviously a very contrived example, but it gives an idea of my point. The main benefit of doing it this way is that my tests aren't tied to any implementations details except the repository. Whereas, if I mocked out the service in my tests, I am now tied to that implementation. If for whatever reason that service layer is removed, all my tests break. I would find it more likely that the service layer is more volatile to change than the repository layer.
The other thing to think about is if I do mock out service in my controller class, I could run into a scenario where all my tests are working properly, but the only way I find out the system is broken is through an integration test (meaning that out of process, or assembly components interact with each other), or through production issues.
If for instance I change the implementation of the service class to below:
public IEnumerable<User> GetActiveUsersThatStartWithLetter(char startsWith)
{
throw new Exception();
}
Again, this is a very contrived example, but the point is still relevant. I would not catch this with my controller tests, hence it looks like the system is behaving properly with my passing "unit tests", but in reality the system is not working at all.
The downside with my approach is that the tests could become very cumbersome to setup. So the tradeoff is balancing out test complexity with abstraction/mockable implementations.
Key thing to keep in mind is that TDD gives the benefit of catching regressions, but it's main benefit to is to help design a system. In other words, don't let the design dictate the tests you write. Let the tests dictate the functionality of the system first, then worry about the design through refactoring.
I realize it may sound like an odd request, and it certainly will not do wonders for test performance, but it's critical that I get a new AppDomain for the start of each unit test.
Currently I'm using xUnit and Resharper as the test runner. But I'm willing to change if there's a different framework that would yield the behaviour that I need.
The xunit resharper runner doesn't have this kind of functionality, and I don't know any test framework that does this out of the box. If you need each test to run in a new AppDomain, I'd write it so that each test created a new AppDomain and ran some custom code in there.
You could probably use some of xunit's features to make this a little easier - the BeforeAfterTestAttribute allows you to run code before and after, or you could pass in a fixture that provides functionality to setup/teardown the AppDomain.
I created a demo Web API application that utilizes Ninject. The application works fine as I can run it, navigate to the defined route, and get the data I'm expecting. Now I want to begin adding unit tests to test the ApiController.
How do I instantiate a new ApiController? I'm using var sut = new DogsController(); but that results in an error, "... does not contain a constructor that take 0 arguments". It's correct I don't have a constructor that takes 0 arguments but Ninject should be taking care of that for me, correct? How do I resolve this?
You will have wired Ninject into the Web API application, not your unit test project. As a result, Ninject will not be creating the dependencies for your controller, or even your controller as you are explicitly creating it (in the Web API application, the framework creates your controller).
You could wire Ninject into your unit test project, but that would not be the correct thing to do. You should be creating your controller in your tests with a known state, so you should either be passing in known dependencies, or passing in some form of mock dependencies.
A DI container is not some piece of magic that transforms your code every time you write "new Something()". In your unit test you are newing up the controller by hand (which is good practice btw), but this means you will have to supply the constructor with the proper fake versions of the abstractions the constructor expects.
How can we unit test a servlet with an embedded Jetty server?
For example, how to test the servlet method below?
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//any logic inside
}
I vastly prefer testing servlets with an embedded instance of jetty using something like junit to bootstrap it.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/MinimalServlets.java
that is the minimal example of how to do it.
This is also how we test the vast majority of jetty itself, starting it up and running it through its paces.
For a specific servlet or handler we often use the jetty-client or a SimpleRequest in our jetty-test-helper artifact. A URLConnection works as well.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.toolchain.git/tree/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/SimpleRequest.java
Here is a test in the jetty-client, it is for jetty-9 so if you want 7 or 8 then look under the corresponding tag, it was refactored quite a bit in jetty-9.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
Note: I recommend you pass 0 as the port for jetty to start up with and that will give you an random open port which you can then pull out of jetty for testing purposes, this avoids the situation where multiple builds are running on CI or parallel builds where there might be a port conflict.
You don't need Jetty to test the servlet, you need a unit testing framework, such as JUnit, Mockito, JMock, etc.
Generally speaking, you don't want to use a servlet container when you do unit testing because you want to focus your test on the actual method being tested, having jetty in the way means that you're also testing jetty behavior. After you've done all your unit tests you can move on to integration tests and system tests, and that part can involve external systems such as jetty (using automation frameworks such as Selenium.)
I use Mockito and PowerMock to do my unit testing, you can check out this code for a working example of a real online service (which you can find here).
I wrote a tutorial about this service and what it contains, this can be found here.
[Added after getting downvotes from time to time on this answer]: And at the risk of getting even more downvotes, all you downvoters need to read the definition of UNIT TESTING before you click the -1 button. You just don't know what you're talking about.