Its being a few months since I am working with java legacy code, this are some of the things I am dealing with:
0% test coverage.
Huge functions in occasions I even saw some with more than 300 lines of code.
Lots of private methods and in occasions static methods.
Highly tight coupled code.
At the beginning I was very confused, I found difficult to use TDD in the legacy. After doing katas for weeks and practicing my unit testing and mocking skills, my fear has decreased and I feel a bit more confident. Recently I discovered a book called: working effectivelly with legacy, I didn't read it, I just had a look at the table of contents and I discovered something that is new for me, The Seams. Apparently this is very important when working in the legacy.
I think that this Seams could help me alot in breaking dependencies and make my code testeable so I can increase the code coverage and make my unit testing more precise.
But I have a lot of doubts:
Can somebody explain me the difference between a seam and a mock?
Do Seams, break TDD rules in what regards not touching production code, before is tested?
Could you show me some simple example that compares a Seam and a Mock?
Below I would like to paste an example I did today where I tried to break a dependency with the goal of making the code testeable and finally increasing test coverage. I would appreciate if you could comment a bit if you see some mistakes?
This is how the legacy code looked like at the beginning:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(HttpServletRequest request) {
String [] values = request.getParameterValues(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
If I just add a unit test that calls that method and asserts that variable output, has a certain value after the call,then I would be making a mistake, because I am not unit testing, I would be doing integration testing. So what I need to do, Is get rid of the dependency I have in the parameter. To do So, I replace the parameter with an interface:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(ParameterSource request) {
String [] values = request.getParameters(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
This is how the interface looks like:
public interface ParameterSource {
String[] getParameters(String name);
}
The next thing I do, is create my own implementation of that interface but I include the HttpServletRequest as a global variable and I implement the method of the interface using the method/s of HttpServletRequest:
public class HttpServletRequestParameterSource implements ParameterSource {
private HttpServletRequest request;
public HttpServletRequestParameterSource(HttpServletRequest request) {
this.request = request;
}
public String[] getParameters(String name) {
return request.getParameterValues(name);
}
}
Until this point, I think that all the modifications on the production code were safe.
Now I create the Seam in my test package. If I understood well, now I am able to safely change the behavoir of the Seam. This is how I do it:
public class FakeParameterSource implements ParameterSource {
public String[] values = {"ParamA","ParamB","ParamC"};
public String[] getParameters(String name) {
return values;
}
}
And the final step, would be to get support from the Seam, to test the original behavoir of the method.
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import code.ABitOfLegacyRefactored;
import static org.hamcrest.Matchers.*;
public class ABitOfLegacySpecification {
private ABitOfLegacy aBitOfLegacy;
private String EMPTY = null;
#Before
public void initialize() {
aBitOfLegacy = new ABitOfLegacy();
}
#Test
public void
the_output_gets_populated_when_the_request_is_not_empty
() {
FakeParameterSource fakeParameterSource = new FakeParameterSource();
aBitOfLegacy.doSomeProcessing(fakeParameterSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
#Test(expected=NullPointerException.class)
public void
should_throw_an_exception_if_the_request_is_null
() {
aBitOfLegacy.doSomeProcessing(null);
}
}
This will give me 100% test coverage.
I appreciate your thoughts:
Did I break the dependency correctly?
Are the unit tests missing something?
What could be done better?
Is this example good enough to help me understand the difference between a Seam and a Mock?
How could a mock help me here if I don't use the Seam?
A seam is a place in the code that you can insert a modification in behavior. You created a seam when you setup injection of your dependency.
One way to take advantage of a seam is to insert some sort of fake. Fake's can be hand-rolled, as in your example, or be created with a tool, like Mockito.
So, a mock is a type of fake, and a fake is often used by taking advantage of a Seam.
As for your tests and the way you broke the dependency, that's pretty much how I would have done it.
Seams
A seam is a place that allows you to modify the behavior without modifying the code.
In your example, the following is an example of an Object seam (if i'm not mistaken). It allows you to pass in a different object without having to change the code. hence it is a type of seam.
public void doSomeProcessing(ParameterSource request) {..}
By making the parameter an abstract type (instead of a concrete class), you have introduced a seam. The seam now allows you to modify the behavior of the method without editing its code - i.e. at the place of invokation, I can pass in a different object and make the method do something else.
Mocks
Now instead of creating your custom fake (creating a subtype of the interface), you could using a Mock framework to do something like this
Mocks also support asserting whether specific methods were called on it, argument matching and other nifty functionality to be consumed by tests. Less test code to maintain. Mocks are primarily used to assert that a specific call is being made to a dependency. In your example, you seem to be in need of a Stub, you just want to return a canned value.
Pardon my rusty JMock..
#Test
public void
the_output_does_not_get_populated_when_the_request_is_empty
() {
Mockery context = new Mockery();
final ParameterSource mockSource = context.mock(ParameterSource.class)
context.checking(new Expectations(){{
oneOf(mockSource).getParameters();
will(returnValue(new string[]{"ParamA","ParamB","ParamC"} );
}});
aBitOfLegacy.populate(mockSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
in .Net
var mockSource = new Mock<ParameterSource>();
mockSource.Setup(src => src.GetParameters())
.Returns(new []{"ParamA","ParamB","ParamC"});
Related
I have a class that I am trying to unit test. This class extends another class that I am not interested in unit testing at this time.
The following code is an over simplification of the code I am trying to test.
package com.example.somePackage;
public class ApiBase {
protected <T extends SomeClass> t getApi(Class<T> apiClass) {/* some logic*/}
}
package com.example.anotherPackage;
public MagicApiImpl extends ApiBase {
private final MagicApiHandler apiHandler = new MagicApiHandler();
public String doSomeStuff(String someString) {
final BookApi bookApi = getApi(BookApi.class);
// some logic
return apiHandler.someMethod(bookApi, someString);
}
}
I would like to test doSomeStuff() on MagicApiImpl The part I would like to mock is what comes back in getApi().
At first go I tried simply creating an Instance of MagicApiImpl and setting all the behind the scenes things that happen but that started to become over complex for the scenario I want to test and the number of times I need to test it in other classes. I will handle the testing of the logic in getApi() in a test of its own.
It would be helpful to use EasyMock to test this as it is what a majority of the tests for this project are written in but I would not be overly apposed to using mockito.
Edit
Okay I was reading about the Mockito.spy() That would have been wonderful but sadly getApi is protected and in another package. Worst case I could fall back on placing all the tests in that package but that makes it difficult track code.
Using Easymock partial mocks your test should look like this:
#Test
public void test() {
MagicApiImpl impl = EasyMock.createMockBuilder(MagicApiImpl.class)
.addMockedMethod("getApi")
.createMock();
EasyMock.expect(impl.getApi(BookApi.class)).andReturn(/**Wharever you need*/);
EasyMock.replay(impl);
String input = "INPUT";
String output = impl.doSomeStuff(input);
System.out.println("The OUTPUT is: " + output);
EasyMock.verify(impl);
//Run asserts here
}
Reference: http://easymock.org/user-guide.html#mocking-partial
I am new to writing tests in java, and seem to be unable to test if a method of a class is called.
I am sending metrics to datadog, and want to test in the code if a function of another class was called.
It says I need to mock first, but I couldn't get it to work.
MetricRecorder.java
import com.timgroup.statsd.StatsDClient;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.google.common.base.Preconditions;
public class MetricRecorder {
private final String namespace;
private final static StatsDClient metrics = new NonBlockingStatsDClient(
"my.prefix",
"localhost",
8125,
new String[] {"tag:value"}
);
public MetricRecorder(String namespace) {
Preconditions.checkNotNull(namespace);
this.namespace = namespace;
}
public void inc(String metricName) {
this.inc(metricName, 1);
}
public void inc(final String metricName, final long value) {
Preconditions.checkNotNull(metricName);
try {
metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value);
} catch (Exception e) {
logger.warn("Unable to record metric {} due to :", metricName, e);
}
}
...
}
MetricRecorderTest.java
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
MetricRecorder recorder = new MetricRecorder("dev");
recorder.inc("foo", 1);
verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1);
}
}
When I run the test I get this => org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type NonBlockingStatsDClient and is not a mock!
Any idea of how I should be testing if recordHistogramValue was called, and if so with what arguments?
Since it looks like StatsDClient is an interface of some kind, it would make your testing effort easier to simply inject this dependency into your object. Even if you're not using an IoC container like Spring or Guice, you can still somewhat control this simply by passing an instance of it in through the constructor.
public MetricRecorder(String namespace, StatsDClient client) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(client);
this.namespace = namespace;
this.client = client;
}
This will make your testing simpler since all you realistically need to do is mock the object passed in during test.
Right now, the reason it's failing is because you're newing up the instance, and Mockito (in this current configuration) isn't equipped to mock the newed instance. In all honesty, this set up will make testing simpler to conduct, and you should only need your client configured in one area.
#RunWith(MockitoJUnitRunner.class)
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
StatsDClient dClientMock = Mockito.mock(StatsDClient.class);
MetricRecorder recorder = new MetricRecorder("dev", dClientMock);
recorder.inc("foo", 1);
verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1);
}
}
You are getting things wrong here. You don't use a mocking framework to test your "class under test".
You use the mocking framework to create mocked objects; which you then pass to your "class under test" within a test case. Then your "code under test" calls methods on the mocked object; and by controlling returned values (or by verifying what happens to your mock); that is how you write your testcases.
So, your testcase for a MetricRecorder doesn't mock a MetricRecorder; it should mock the StatsDClient class; and as Makoto suggests; use dependency injection to put an object of that class into MetricRecorder.
Besides: basically writing "test-able" code is something that needs to be practiced. I wholeheartedly recommend you to watch these videos if you are serious about getting in this business. All of them; really (worth each second!).
Let's say I have the following classes in the respective source folders/packages...
[src/myApp]
|_Employee «concrete»
|_Manager «abstract»
|_ManagerImpl «concrete» (Class Under Test)
|_Recruiter «abstract»
|_RecruiterImpl «concrete» (Collaborator)
...
public class ManagerImpl implements Manager {
...
private Recruiter recR;
...
public void growTeam( Object criteria ){
//...check preconditions
Employee newB = recR.srcEmployee( criteria );
//...whatever else
}
...
}
...
[test/myApp]
|_RecruiterStandIn «concrete»
|_ManagerImplTest
...
public class RecruiterStandIn implements Recruiter {
Map<Object, Employee> reSrcPool = new HashMap<>();
public RecruiterStandIn( ){
// populate reSrcPool with dummy test data...
}
public Employee srcEmployee( Object criteria ){
return reSrcPool.get( criteria );
}
}
...
public class ManagerImplTest {
...
// Class Under Test
private ManagerImpl mgr;
// Collaborator
private Recruiter recR = new RecruiterStandIn( );
...
public void testGrowTeam( ) {
//...
mgr.setRecruiter( recR );
mgr.growTeam( criteria );
// assertions follow...
}
...
}
...
Here are my questions: Given that I have a RecruiterStandIn concrete implementation that already exists within the codebase for testing purposes (in the test scope)...
Would it be redundant to also use a mock in the above unit test?
What would be the value (if any) in additionally doing something like this in the above unit test?
...
...
#Mock
private Recruiter recR;
...
...
public void testGrowTeam( ) {
...
expect( recR.srcEmployee( blah) ).andReturn( blah )...
// exercising/assertions/validations as usual...
}
...
You can safely assume that RecruiterStandIn does everything the class under test will ever require of it for the purposes of the above unit test. That is to say, for the sake of simple answers/explanations, there's no need to overcomplicate the above scenario with contrived what-ifs around maintenance of the stub and whatnot.
Thanks in advance.
My answers to your specific questions:
Would it be redundant to also use a mock in the above unit test?
As the unit test is written right now it would be redundant but my see answer to your second question below.
What would be the value (if any) in additionally doing something like this in the above unit test?
It think this is the way you should be doing your tests and I would recommend getting rid of your stub, RecruiterStandIn. Instead I would setup the recruit to return canned answers so you don't have to maintain two classes just to return some predefined data:
#Spy
private Recruiter recR;
public void testGrowTeam( ) {
// Setup canned data return
doReturn(generateTestEmployee()).when(recR).srcEmployee(any(Object.class));
expect( recR.srcEmployee( blah) ).andReturn( blah )...
// exercising/assertions/validations as usual...
}
FYI the above syntax would be for using Mockito. From what I can tell in your case Mockito gives you the power of stubbing out certain parts and much more without requiring you to create new test entities.
Original Answer
Definitely yes you should be doing mock object tests. Mocks Aren't Stubs. Mock object testing allows you to test the interactions between your classes and ensure that things are interacting with the world around them correctly. I think there is less value in these tests when you first write the classes and their corresponding tests. Mock object tests shine a year down the road when a new developer comes in and inadvertently your breaks code because she didn't understand that certain internal behavior was needed..
A somewhat contrived example would be if let's say we had a Car that needed to fill up some gas:
public class Car {
public void fuelUp()
}
Now with standard unit tests we would check that after calling fuelUp() the car was full of gas and that the proper amount of money was deducted from the driver. But since we never tested how fuelUp() was interacting with the world around it, it could easily be doing the following:
public void fueldUp() {
siphonGasFromNearestCar();
buyCoffeeAndChips()
}
But with mock object testing you can ensure that the Car is getting filled up in the proper and expected way.
I have a class with a few methods advised through an input validation aspect (validates whether all input parameters are not-null/non-empty strings).
I am facing an issue while writing test case for them and want to verify if this is indeed a bad design issue.
Here's a very simplified version of my class:
public class A {
public String one(String word) {
// Some actions
String val = two(word2);
// Some more actions
}
protected String two(String word) {
// Some actions
}
}
Now while writing test cases for one() I use Mockito and want to mock calls to two(). So I use:
#Spy
A a;
#Test
void test() {
doReturn("Bye").when(A).two(Mockito.anyString());
a.one("hello");
// Some validations
}
This test fails as the: doReturn() line fails with input being empty for two().
Should I not mock two() or can I make this work somehow?
Edit:
Adding a more specific example related to the two methods being present in two different classes as requested:
Create a page through a WebService. This builds a putRequest, executes it and returns a response.
public class AUtility implements BaseUtility {
public Response create(Params params) {
try {
PutMethod putRequest = buildPUTRequest(params.getAttr1(), params.getAttr2());
return Utils.buildResponse(client.executeMethod(putRequest),
params.getAttr3(),
params.getAttr4());
} catch (Exception e) {
throw new AppException(e);
}
}
}
The put request marshals the data into a file to write it through the HttpClient
private PutMethod buildPUTRequest(final String url, final Object obj) throws IOException, JAXBException {
// Create a temp file to store the stream
File tempFile = File.createTempFile(APPLICATION_LABEL, XML_LABEL);
decoder.marshal(obj, tempFile);
// Build the put method
return putMethod;
}
XMLMarshaller
public interface XMLDecoder implement Decoder {
public void marshal(Object obj, File tempFile) throws IOException, JAXBException {
// Perform marshalling operations
}
}
The test fails on line2 with the inputs being null.
#Test
public void createPageParamsHttpException() throws HttpException, IOException, JAXBException {
expectedException.expect(AppException.class);
doNothing().when(decoder).marshal(Mockito.anyString(), Mockito.any(File.class));
doThrow(HttpException.class).when(client).executeMethod(Mockito.any(HttpMethod.class));
Params params = new Params(new Application(),
APPLICATION_URL_LABEL,
SITE_NAME_LABEL,
URL_WITHOUT_HTTP_N_HTML);
utility.createPage(params);
}
Any idea how should I proceed for the same?
You don't want to do this.
You are inherently changing the behavior of the class. If you change what two() does, how do you know that one() will do what it's supposed to do in production?
If you truly want to do this, you should extract the behavior of two() into another top level class, and then inject the dependency into A. Then you can mock this dependency and you don't have to worry about going to the trouble of creating a partial mock for A.
In a similar vein, if you must keep two in the same class (because it's behavior is part of the same responsibility that is assigned to A - see the Single Responsibility Principle - why is it public?
The reason you are having trouble is because you are violating the SRP, see my note above. You said this:
This builds a putRequest, executes it and returns a response.
You should not be trying to test the behavior of all three of those things at the same time. Ultimately, this method does not really do anything. The buildPUTRequest method does, and shouldn't be in a class called AUtility, it should be in a class RequestFactory. Then, you would want to test the Utils.buildResponse method, except that shouldn't be in a class called Utils, it should be in a class called Responder or something... and this method ABSOLUTELY should not be static.
Work on naming your classes better things, and if you can't come up with a good name, that means the class probably does too much and should be refactored. And a method that wraps the work in two other methods doesn't need to be unit tested. Integration tested, perhaps, but that's another story.
For public method calls, EasyMock's capture() allows you to intercept & examine arguments passed to the method. For private method calls, PowerMock's expectPrivate lets you mock private method calls.
Is there a way to somehow combine these and get the arguments passed to a private method call? Example:
public class Program
{
public FancyReturnType PublicMethod()
{
ArbitraryType localInstance = new ArbitraryType();
localInstance.setFoo(somePrivateHelperMethod());
localInstance.setBar(increasinglyComplexMagic());
long aLongValue = 11235L;
// more variables, more work
SomeType worker = privateHelperToIntercept(localInstance, aLongValue, otherVariables);
if (worker.something)
{
return retVal.aFancyReturnType;
}
else
{
return retVal.anotherFancyReturnType;
}
}
}
In this case, I want to examine the localInstance object as it is consumed by the privateHelperToIntercept() call.
I've found plenty of examples to mock private method calls; PowerMock's expectPrivate(partiallyMockedObject, "nameOfPrivateMethod", arg1, arg2) works great. I've also found examples to intercept arguments passed to public method calls; Capture<Type> myTestCapture = new Capture<Type>() combined with someMockedObject.PublicMethod(capture(myTestCapture)).
Unfortunately, I can neither get the two to work together, nor find examples of combining them. Has anyone seen a way to do this?
FWIW, I suspect Mockito can do this, but it's not included in our source/build/test system. I'd like to avoid the process of supporting new libraries in our system if possible.
If you are asking how to get a reference to localInstance, then the following code should suffice.
#PrepareForTest(Program.class)
public class Test {
#Test
public void testMethod() {
ArbitraryType passedLocalInstance = new ArbitraryType();
PowerMock.expectNew(ArbitraryType.class).andReturn(passedLocalInstance );
//remainder of the test method
assertEquals(14.2, passedLocalInstance .getValue());
}
}
Since java is pass-by-reference, the passedLocalInstance will be the argument passed into the method call. Did that answer your question?
new of any type is simply a static method. Deal with it in the same way... wrap it in a method, stub out the method. In this case you want to return a mock in your test, and then you can test all the interactions with that object (and remove dependency in your test on the code within the object you are creating which should have it's own tests)
public Program {
// your above code up to object creation
ArbitraryType localInstance = createArbitraryType();
// rest of your above code here
ArbitraryType createArbitraryType() {
return new ArbitraryType();
}
}
in your test...
public class MyTest {
TestableProgram extends Program {
#Override
ArbitraryType createArbitraryType() {
return this.arbitraryTypeMock;
}
}
private ArbitraryType arbitraryTypeMock;
private TestableMyClass objectToTest = new TestableProgram();
// rest of your tests...
}
Given your constraint's that's how I'd do it.
If could bend your constraints a bit I'd loosen up on the private methods, I've generally done away with private in favor of package default to make testing easier. If the folks IN your package are misbehaving, it's usually your code so private is mostly protecting you from yourself anyway. (but I know that isn't a valid answer your question as posed... ).