Test Retrieval from Data Structure without testing Store - java

Let's say I want to write some JUnit tests for a new, untested data structure BlackBox. It has an interface similar to a Map, but there's no way to tell what is going on inside of it:
blackBox.get(key);
blackBox.put(key, value);
How do I correctly unit test .get and .put in the two following scenarios? I cannot figure out how to test the two independently.
I am using TDD, and therefore want to write the tests first.
BlackBox has been written by someone else and I want to test it.
I know that if I had access to the source, I can do the following:
Whitebox.setInternalState(blackBox, "storage", storageObject);
assertEquals(blackBox.get("key"), expectedAnswer");
I can do the opposite to test .put(). The issue is that those tests rely on the implementation of the class.
So how can I individually test .get and .put without knowing or relying on the implementation details of the class?

I cannot figure out how to test the two independently.
why do you want to do that? does the contract state they are independent? i don't think so. i'm guessing the contract says:
new object is created as empty so get will return null / throw exception.
when you put something, you can get it.
you can not get what you didn't put.
when you put many times on same key you will get the latest value.
and so on. you can test each of those invariants. when you use Whitebox you start to test implementation details, not the contract and that makes the refactoring (e.g. using faster implementation) much harder

Related

How to manage huge sized classes and refactoring in unit testing (junit)

In our project which has huge sized classes and sub relations we have been developing for months. Also, we have been developing junit test cases.
Automatic unit tests are good in general, but in real life it is not easy as we think. Managing the unit test architecture is easier than creating mock objects and stubs etc. Also, we are testing the dao and service layers.
The problem is that our classes have so many attributes. (I know it's not a good object oriendted design but it's legacy architecture.)
For example; customer class has 58 attributes and it's related to address, marsaccounts and etc. Totally if you want to test this class you have to create inputs, inputs with 90 or more attributes.
Our architecture has many business rule on Customer, so that we have to create more than 50 customer inputs to test every rule, method or flow.
In short, you have to create 4500 (90 x 50) attributes for all, but less for a reliable test (only necessary attributes).
Preparing the test inputs are painful and annoying. Imagine, 2 columns added to Customer object and they store critical values. it seems easy, but refactoring the test inputs are soul-destroying.
How can I manage the test stub and How can I overcome the huge input set ?
Regards.
it looks like you have only two options: make less attributes relevant or learn to easily set-up tests with large number of attributes.
less attributes: refactor. and no one will give you much more detailed help because we don't know your business. try to find smaller groups of attributes that control some logic and test that logic using only those attributes.
easy test set-up: you can use customer builders. by default they create customer with some standard/most common settings and you tune the result however you want like
customer = makeCustomer().withActiveStatus(false).withDebit(3000).build()
Then, when new attribute appears you just have to change makeCustomer() in one place.
you can also use parameterized tests to define a test case as a one liner or load data from spreadsheet which may be easier to maintain.
Often when new attribute appears it's not that it changes everything completely. usually it just adds new behaviour in one spot when that attribute is non-standard. therefore usually it's just adding the default attribute to the builder and a few tests that override that attribute
another way to make tests easy is to do property testing (QuickCheck family) although not always it's easy to use it in business logic
Use mocked customer. Setup only attributes that relevant for rule that you want test.
As mentioned in the other answers, your best bet is to refactor those huge classes towards more fine-grained classes with a single responsibility, but in order to get your legacy code under test it might be worth looking into the test data builder pattern.
In essence, test data builders provide an abstraction that hides away object construction. For example, they can provide default values for all constructor arguments, allowing you to specify the relevant ones in each of your tests (often through a fluent API which make your tests very readable).
new AddressBuilder()
.withName("Sherlock Holmes")
.withStreet("221b Baker Street")
.withCity("London")
.withPostCode("NW1", "3RX")
.build();
In short, you have to create 4500 (90 x 50) attributes for a reliable
test.
No, you don't. You're not thinking about this right. You might need 4500 attributes for an exhaustive test, but not for a reliable test.
Mocking is an entirely legitimate and "real" - you're word - means of testing, and it's the appropriate answer here.
There are several ways to make your code and tests more manageable.
customer class has 58 attributes and it's related to address, marsaccounts and etc.
That's too many attributes for a single class. You should try to refactor the class and break it up into many classes. You mention addresses, if you have many attributes related to different fields of an address, you should refactor those out into an Address object. Finding other similar related fields and pulling them out into their own objects will really help reduce the number of inputs and make it easier to mock in tests.
Preparing the test inputs are painful and annoying. Imagine, 2 columns added to Customer object and they store critical values. it seems easy, but refactoring the test inputs are soul-destroying.
I would suggest making a Customer TestDouble for tests. By default, this TestDouble will be initialized to have all 58+ attributes set to valid values. The TestDouble will also have setters for all these values so they can be changed for each tests.
This way your test code doesn't duplicate setting all the irrelevant fields and makes the test more intent revealing.
For example:
#Test
public void invalidAccountIdShouldThrowBusinessRuleException(){
CustomerTestDouble cust = new CustomerTestDouble();
//only set what matters for this test
cust.setMarsaccount( -1);
BusinessRuleValidator validator = ...
//wrap with whatever you do to check that validator throws Exception
validator.validate(cust);
}
This is very clear that the exception will be thrown because the account id is -1 there's no other clutter.
And if you have to add new fields to Customer later, (or refactor it to use new objects) most of your test code is unchanged. Only the CustomerTestDouble and any directly affected tests need to be changed.

Unit testing and too many mocks

I'm starting to practice TDD in my project, as a background it also contains legacy code. We use Mockito as a mocking framework and follow a Spring MVC approach.
There are times when there's a Service class implemented with many different DAO objects as #Autowired properties. There are simple methods within these services, like for example completeTransaction.
completeTransaction will use many of the DAO objects to complete its responsibilities
Update and save the transaction
Advance a business process
Closing other pending operations
However, in performing those operations, the method requires calls to different DAO to fetch and update the transaction, fetch a business process ID, fetch pending transactions (and save their updates). This means that unit testing this method makes me add many #Mock properties. And I need to set up the mock objects before the test will actually finish for me to test a certain condition.
This seems like a code smell, and to me it almost feels like the test is ensuring the implementation of the code instead of just its contract. Again, without mocking the dependencies, the test case will not run (due to NPE and others).
What is a strategy that I can follow to clean up code like this? (I can't really provide the actual source code on the question though). I'm thinking that one possibility would be to set up a facade class with methods like ("getPendingOperations" and "advanceBusinessProcess"). Then I can mock a single dependency. But then I figure that in all other classes that have situations like this I would need to do the same, and then I'm afraid to end up with a lot of "helper" classes just for the sake of cleaner tests.
Thank you in advanced.
I think you'll want to do two things in general when you find yourself with too many mocks. These are not necessary easy, but you may find them helpful.
1) Try and make your methods and classes smaller. I think Clean Code says there are two rules, that classes should small. And that classes should be smaller then that. This makes some sense because as the units you are testing (methods and classes) get smaller, so will the dependencies. You will of course end up with more tests, but they will have less setup in each test.
2) Look at the Law of Demeter (https://en.wikipedia.org/wiki/Law_of_Demeter). There are a bunch of rules, but basically, you want to avoid long string of property/method calls. objA = objB.propertyA.SomeMethod().propertyC; If you need to mock out all of these objects just to get objA, the you will have a lot of setup. But if you can replace this with objA = objB.newProperty; then you only need to mock objB and it's one property.
Neither of these are silver bullets, but hopefully you can use some of these ideas with your project.
If the unit test is testing the completeTransaction method, then you must mock everything on which it depends. Since you are using Mockito, you can use verify to confirm that the correct mocked methods are called and that they are called in the correct order.
If the unit test is testing something that calls the completeTransaction method, then just mock the completeTransaction method.
If this is your class hierarchy:
class A -> class B -> class C
(where -> is "depends on")
In unit tests for class A, mock only class B.
In unit tests for class B, mock only class C.

Is it enough to just instantiate other domain objects when you do unit testing?

If you test class Car, and want to create a method on it that returns the number of seats. Is it enough to just write car.addSeat(new Seat()) multiple times without actually setting some data on the seat if it isn't needed? The method would look something like:
public int numberOfSeats() {
return seats.size();
}
given that seats is a list of seats. Or would you fill data on the seat even though it isn't needed? Should you always just try to keep the effort on writing tests at a minimum?
You should consider using mocking. With mocking you can control how the object that's not being tested behaves using expectations.
e.g.
when(seat.getSomeProperty()).thenReturn("some value")
But if you don't need the value you can just leave the expectation out of your code. This way the code could be updated without rewriting the test and maintaing your test is much simpler.
Checkout Mockito
https://code.google.com/p/mockito/
I have two approaches in mind.
Define exactly what you want to test and you will know exactly what data needs to be filled. In your example, it wouldn't be neccesary to fill the seats.
If you want to test more than just numberOfSeats, you can use setUp and tearDown to create a reusable set of data for each of your tests. JUnit runs setUp before EACH test, and tearDown after.

DAO test: the right way?

I want to test my class MyTypeDAO implemented with Hibernate 4.1 using JUnit 4.9. I have the following question:
In my DAO, I have a findById method that retrieve an instance of my type by its ID. How to test this method?
What I've done:
I create an instance of my type.
Then, I need to persist this instance, but how? Can I rely on my saveMyType method? I don't think so, since I'm in the test case and this method is not tested.
Then, I need to call the findById method with the ID of the instance created in step 1.
Finally, I check that the instance created in step 1 equals the one I get in step 3.
Any idea? What are the best practices?
I have the same questions for the save method, since after running it, I need to retrieve the save instance. Here also, I don't think I can rely on my findById method since it's not already tested.
Thanks
One possible way is:
Create a in memory db for testing, load contents of this db from a predefined sql script andthen test your DAO classes against this database.
Everytime you start tests, database will be created from scratch using the sql script and you will know which id should return a result and which one should not.
See [DbUnit][1] (from satoshi's comment)
I don't think you have much choice to achieve this. It's not a good practice to have orthognal tests (tests that test 2 things or are dependent). Nevertheless, you should really consider this exception valid and fast. You are right : persisting an object and retrieving it is a good idea to test this dao layer.
Other options include having a record that you are sure about in the database and testing the retrieval (findById) on it. And the a second test to persist an object and removing it the teardown method.
But really, it would be simpler to test loading and saving together and it makes much sense.

Is there a better way to test the following methods without mocks returning mocks?

Assume the following setup:
interface Entity {}
interface Context {
Result add(Entity entity);
}
interface Result {
Context newContext();
SpecificResult specificResult();
}
class Runner {
SpecificResult actOn(Entity entity, Context context) {
return context.add(entity).specificResult();
}
}
I want to see that the actOn method simply adds the entity to the context and returns the specificResult. The way I'm testing this right now is the following (using Mockito)
#Test
public void testActOn() {
Entity entity = mock(Entity.class);
Context context = mock(Context.class);
Result result = mock(Result.class);
SpecificResult specificResult = mock(SpecificResult.class);
when(context.add(entity)).thenReturn(result);
when(result.specificResult()).thenReturn(specificResult);
Assert.assertTrue(new Runner().actOn(entity,context) == specificResult);
}
However this seems horribly white box, with mocks returning mocks. What am I doing wrong, and does anybody have a good "best practices" text they can point me to?
Since people requested more context, the original problem is an abstraction of a DFS, in which the Context collects the graph elements and calculates results, which are collated and returned. The actOn is actually the action at the leaves.
It depends of what and how much you want your code to be tested. As you mentionned the tdd tag, I suppose you wrote your test contracts before any actual production code.
So in your contract what do you want to test on the actOn method:
That it returns a SpecificResult given both a Context and an Entity
That add(), specificResult() interactions happen on respectively the Context and the Entity
That the SpecificResult is the same instance returned by the Result
etc.
Depending on what you want to be tested you will write the corresponding tests. You might want to consider relaxing your testing approach if this section of code is not critical. And the opposite if this section can trigger the end of the world as we know it.
Generally speaking whitebox tests are brittle, usually verbose and not expressive, and difficult to refactor. But they are well suited for critical sections that are not supposed to change a lot and by neophytes.
In your case having a mock that returns a mock does look like a whitebox test. But then again if you want to ensure this behavior in the production code this is ok.
Mockito can help you with deep stubs.
Context context = mock(Context.class, RETURNS_DEEP_STUBS);
given(context.add(any(Entity.class)).specificResult()).willReturn(someSpecificResult);
But don't get used to it as it is usually considered bad practice and a test smell.
Other remarks :
Your test method name is not precise enough testActOn does tell the reader what behavior your are testing. Usually tdd practitioners replace the name of the method by a contract sentence like returns_a_SpecificResult_given_both_a_Context_and_an_Entity which is clearly more readable and give the practitioner the scope of what is being tested.
You are creating mock instances in the test with Mockito.mock() syntax, if you have several tests like that I would recommend you to use a MockitoJUnitRunner with the #Mock annotations, this will unclutter a bit your code, and allow the reader to better see what's going on in this particular test.
Use the BDD (Behavior Driven Dev) or the AAA (Arrange Act Assert) approach.
For example:
#Test public void invoke_add_then_specificResult_on_call_actOn() {
// given
... prepare the stubs, the object values here
// when
... call your production code
// then
... assertions and verifications there
}
All in all, as Eric Evans told me Context is king, you shall take decisions with this context in mind. But you really should stick to best practice as much as possible.
There's many reading on test here and there, Martin Fowler has very good articles on this matter, James Carr compiled a list of test anti-patterns, there's also many reading on using well the mocks (for example the don't mock types you don't own mojo), Nat Pryce is the co-author of Growing Object Oriented Software Guided by Tests which is in my opinion a must read, plus you have google ;)
Consider using fakes instead of mocks. It's not really clear what the classes in question are meant to to, but if you can build a simple in-memory (not thread-safe, not persistent etc) implementation of both interfaces, you can use that for flexible testing without the brittleness that sometimes comes from mocking.
I like to use names beginning mock for all my mock objects. Also, I would replace
when(result.specificResult()).thenReturn(specificResult);
Assert.assertTrue(new Runner().actOn(entity,context) == specificResult);
with
Runner toTest = new Runner();
toTest.actOn( mockEntity, mockContext );
verify( mockResult ).specificResult();
because all you're trying to assert is that specificResult() gets run on the right mock object. Whereas your original assert doesn't make it quite so clear what is being asserted. So you don't actually need a mock for SpecificResult. That cuts you down to just one when call, which seems to me to be about right for this kind of test.
But yes, this does seem frightfully white box. Is Runner a public class, or some hidden implementation detail of a higher level process? If it's the latter, then you probably want to write tests around the behaviour at the higher level; rather than probing implementation details.
Not knowing much about the context of the code, I would suggest that Context and Result are likely simple data objects with very little behavior. You could use a Fake as suggested in another answer or, if you have access to the implementations of those interfaces and construction is simple, I'd just use the real objects in lieu of Fakes or Mocks.
Although the context would provide more information, I don't see any problems with your testing methodology myself. The whole point of mock objects is to verify calling behavior without having to instantiate the implementations. Creating stub objects or using actual implementing classes just seems unnecessary to me.
However this seems horribly white box, with mocks returning mocks.
This may be more about the class design than the testing. If that is the way the Runner class works with the external interfaces then I don't see any problem with having the test simulate that behavior.
First off, since nobody's mentioned it, Mockito supports chaining so you can just do:
when(context.add(entity).specificResult()).thenReturn(specificResult);
(and see Brice's comment for how to do enable this; sorry I missed it out!)
Secondly, it comes with a warning saying "Don't do this except for legacy code." You're right about the mock-returning-mock being a bit strange. It's OK to do white-box mocking generally because you're really saying, "My class ought to collaborate with a helper like <this>", but in this case it's collaborating across two different classes, coupling them together.
It's not clear why the Runner needs to get the SpecificResult, as opposed to whatever other result comes out of context.add(entity), so I'm going to make a guess: the Result contains a result with some messages or other information and you just want to know whether it's a success or failure.
That's like me saying, "Don't tell me all about my shopping order, just tell me that I made it successfully!" The Runner shouldn't know that you only want that specific result; it should just return everything that came out, the same way that Amazon shows you your total, postage and all the things you bought, even if you've shopped there lots and are perfectly aware of what you're getting.
If some classes regularly use your Runner just to get a specific result while others require more feedback then I'd make two methods to do it, maybe called something like add and addWithFeedback, the same way that Amazon let you do one-click shopping by a different route.
However, be pragmatic. If it's readable the way you've done it and everyone understands it, use Mockito to chain them and call it a day. You can change it later if you have need.

Categories

Resources