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'
Related
I am running some tests in django but they depend on a response from an outside service. For instance,
I might create a customer and wish to acknowledge it has been created in the outside service.
Once I am done with testing I want to remove any test customers from the outside service.
Ideally, there would be a method similar to setUp() that runs after all tests have completed.
Does anything like this exist?
You can make use of either unittest.TestCase.tearDown or unittest.TestCase.tearDownClass
tearDown(...) is the method gets called immediately after the test method has been called and the result recorded.
but, the tearDownClass(...) is gets called after tests in an individual class have run. That is, once per test class.
IMO, using tearDownClass(...) method is more appropriate since you may not need to check/acknoledge the external service after search test cases of the same class
So Django's testing framework uses a Python standard library module, unittest. This is where the setUp() method comes from.
This library contains another method tearDown() that is called immediately after the tests are run. More info can be found here
I have a service which has two dependencies. One of them is a $http service responsible for making Ajax calls to my Rest API.
Inside my service I have this function:
this.getAvailableLoginOptions = function() {
return $http.get(path.api + '/security/me/twoFA/options').then(function (resp) {
return new TwoFaLoginOptions(resp.data);
});
};
This function gets some options from my API and returns an object.
Now, how should I unit test this function properly? Normally I would just mock the $http service so that when the get function is called with a string parameter ending with '/security/me/twoFA/options' I would return a valid response with options.
But what if some other developer comes in and refactors this function so now it takes the options from another source e.i. another API or from browser's local storage but the function still works perfectly as it returns what it is supposed to do.
So what really unit testing is? Should we test every function as a black box and assume that if we give some input then we expect some particular output OR we should test it as a white box by looking at every line of code inside a function and mock everything but the test will be strongly dependent on all dependencies and the way how I use them.
Is it possible to write a unit test which tests if my function works properly no matter what algorithm or source of data is used to implement it? Or maybe this is actually a part of unit testing to check if my function really uses a dependency in this and that way (in addition to testing the function's logic)?
But what if some other developer comes in and refactors this function so now it takes the options from another source
This is exactly why Dependency Injection is used, because it makes it simple to manage dependencies between objects (easier to break coherent functionality off into separate contracts (interfaces), and thus solve the problem of swapping out object dependencies during runtime or compile time).
For example, you could have a ITwoFaLoginOptions with multiple implementations (service, local storage etc), and then you'll mock the interface get method.
Should we test every function as a black box [...] OR we should test
it as a white box?
In general unit testing is considered white box testing (mocking the dependencies you have in order to obtain predefined responses that help you reach various code paths, while also asserting these dependencies have been called with the expected parameters), while system (or integration) tests would use a black box approach (for example calling the service like a client, assert against the response/DB).
Is there a way to disable the module discovery and explicitly specify what module classes to use?
This is for test performance reasons. The project states that:
"[scanning] it is part of the startup of any Nancy application and is only performed once and the information is then cached."
and that's dandy, but it seems every unit test also does this global scan, and then it's not fast enough.
That information is for application runtime, not testing. When you are testing a Nancy application, using our testing features such as the Browser class Nancy will require you to be explicit about this
You do this by using a combination of the Module(...), Module<T>() or Modules(...) methods during the Browser / ConfigurableBootstrapper setup
The one time that the testing features would use all modules during testing is if you've explicitly called AllDiscoveredModules instead
I'm using ShrinkWrap to start Jetty server in my integration tests.
Problem:
When I start my test jetty-server and than make mockup of my controller - mockup doesn't work!
I suggest that the reason is different classloaders: JMockit - AppClassLoader, Jetty - WebAppClassLoader.
Question:
How to make mocking works fine?
P.S.
I've googled that -javaagent:jmockit.jar option may help. But it doesn't. Is it necessary for maven project based on 1.7 jdk?
ADDITION:
I've written demo to illustrate my problem. You can find it by the reference.
About my demo:
Except of ten stokes of code, it is identical to those project.
I've only added JMockit and a single mock to illustrate the problem.
You should see JettyDeploymentIntegrationUnitTestCase.requestWebapp method: in those method we make mock which doesn't work.
You can check that Jetty & JMockit loads classes by siblings classloaders, so JMockit simply doesn't see Jetty's classes
URLClassLoader
|
|-Launcher$AppClassLoader
|-WebAppClassLoader
The JUnit test in the example project is attempting to mock the ForwardingServlet class. But, in this scenario with an embedded Jetty web server, there are actually two instances of this class, both loaded in the same JVM but through different classloaders.
The first instance of the class is loaded by the regular classloader, through which classes are loaded from the thread that starts the JUnit test runner (AppClassLoader). So, when ForwardingServlet appears in test code, it is the one defined in this classloader. This is the class given to JMockit to mock, which is exactly what happens.
But then, a copy of ForwardingServlet is loaded inside the deployed web app (from the ".class" file in the file system, so not affected by the mocking as applied by JMockit, which is in-memory only), using Jetty's WebAppClassLoader. This class is never seen by JMockit.
There are two possible solutions to this issue:
Somehow get the class object loaded by WebAppClassLoader and then mock it by calling the MockUp(Class) constructor.
Configure the Jetty server so that it does not use a custom classloader for the classes in the web app.
The second solution is the easiest, and can be done simply by adding the following call on the ContextHandler object created from the WebArchive object, before setting the handler into the Jetty Server object:
handler.setClassLoader(ClassLoader.getSystemClassLoader());
I tested this and it worked as expected, with the #Mock doGet(...) method getting executed instead of the real one in ForwardingServlet.
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.