Unit test for sort of random List<Object> - unit-testing

I have a class who's only task is to take a List<Object> and return a sorted List<Object>. For an example the sort method in the class works with a procedure which places the Objects randomly in the list.
Trying to do: to write the test for that sorting method (or class) which must fail if the sorting is in fact just random. That means I need to find the List<Object> order to test I assume.
Code to be tested
class RootLoggerFirstSorter {
List<LoggerConfig> sort(List<LoggerConfig> unSortedList) {
List<LoggerConfig> levelSortedList = new ArrayList<>(unSortedList);
Collections.sort(levelSortedList, new Comparator<LoggerConfig>() {
#Override
public int compare(LoggerConfig o1, LoggerConfig o2) {
if (o1.getLevel().intLevel() == o2.getLevel().intLevel()) {
return 0;
} else if (o1.getLevel().intLevel() < o2.getLevel().intLevel()) {
return 1;
} else {
return -1;
}
}}
);
LinkedList<LoggerConfig> sortedList = new LinkedList<LoggerConfig>();
for(Iterator<LoggerConfig> i = levelSortedList.iterator(); i.hasNext();) {
LoggerConfig cfg = i.next();
addNextLoggerConfig(cfg, sortedList);
}
return sortedList;
}
private void addNextLoggerConfig(LoggerConfig cfg, LinkedList<LoggerConfig> sortedList) {
if(cfg.getName() == null || cfg.getName().isEmpty()) {
sortedList.addFirst(cfg);
} else {
sortedList.addLast(cfg);
}
}
}
Tried
.....
expect(item1.getLevel()).andStubReturn(Level.DEBUG);
expect(item2.getLevel()).andStubReturn(Level.ERROR);
expect(item3.getLevel()).andStubReturn(Level.INFO);
.....
//Ignore the pre req for test setup
#Test
public void testSort() {
List<LoggerConfig> unsortedList = makeUnsortedList();
EasyMock.replay(item1,item2,item3);
List<LoggerConfig> sortedList = tested.sort(unsortedList);
assertThat("First item on the list is ERROR level: ", sortedList.get(0).getLevel(), is(Level.ERROR) );
assertTrue(sortedList.get(1).getLevel().equals(Level.INFO) || sortedList.get(1).getLevel().equals(Level.INFO));
assertTrue(sortedList.get(2).getLevel().equals(Level.DEBUG) || sortedList.get(2).getLevel().equals(Level.DEBUG));
}
But this test will always pass since if looked at the index 1 and 2 only, index 0 will always contain the LoggerConfig with an empty name [set up is done that way]). So I thought Should I just unit test the compare method instead? If yes, how?
Problem The issue is that I need to test the sort method with a particular Object property which is the level of the LoggerConfig object. So the test must check the List order.

Many different aspects here:
Of course you do not need to test the built-in Collections.sort() method.
In that sense: instead, you want to test two aspects A) that you are actually calling that sort method B) that your comparator works as expected.
A) is achieved by the code you put in your own answer. Or to be precise: you only need one test case where you sort check for an expected result; after providing a specific test input to your method.
B) is achieved by writing test code that simply checks that compareTo() returns the expected result for the different input
In the end, this is about properly dissecting your logic into classes. Of course you can declare that comparator as anonymous inner class; and just verify that the sort method returns the expected result.
But when you make the comparator, say an inner class somewhere, you could write unit tests for just the comparator functionality.
Finally: your test case does not mean the goal that you stated: must fail if the sorting is in fact just random. You see, if the result of sort() is random, that it could randomly give you a correct result. Meaning: you can't expect a single test to verify "possibly random behavior". You would have to run many tests with a lot of different data, and verify that all of them pass; to achieve a certain confidence that the sort() isnt pure random.
But as said: you are not sorting. You are calling the built-in sort method which does not need to be tested.

I assumed the List<ConfigLogger> followed something like item1["", ERROR], item2["com.fwk.foo", DEBUG], item3["com.fwk.core.baa", INFO]. So in that case I needed to check that if item3 is in the position 1 and item2 is in position 3 in the list the implementation does the sort correctly. So test I needed was as follows:
#Test
public void testSort() {
List<LoggerConfig> unsortedList = makeUnsortedList();
EasyMock.replay(item1,item2,item3);
List<LoggerConfig> sortedList = tested.sort(unsortedList);
assertFalse(unsortedList.equals(sortedList));
assertTrue(sortedList.get(0).getName().isEmpty());
LoggerConfig cfg1 = sortedList.get(1);
LoggerConfig cfg2 = sortedList.get(2);
assertThat(cfg1.getLevel(), is(Level.DEBUG));
assertThat(cfg2.getLevel(), is(Level.INFO));
}
So I am accessing the item from the list and comparing if they are same as expected.

Should I just unit test the compare method instead?
No, you should not. The test may fail if you try to refactor the sort method later. You are actually trying to assert that the sorting is done probably. The compare method is just an implementation detail. You may not use the compare method to sort the list in the future.
Of course you also don't need to test the built-in sort method because you are actually testing your custom sort method. Anything inside this sort method is implementation details including the list.sort method you called. You should pretend that you don't know about it when you are writing a test.
Other than that, your sort method also contain some logic that is not related to the built-in sort method.

Related

How to use testing::_ in an EXPECT_CALL, excluding 2 values?

I have a method, which inside calls a method which returns bool value - in this question let's name the method:
bool IsFilled(int value)
Now in another method which I am testing this is being called multiple times:
if (IsFilled(0))
{
if (IsFilled(1)){
...
} else {
...
}
}
for (int i = 1; i < range; i++)
{
if (IsFilled(i)) {
...
if (IsFilled(0)) {
}
}
}
Now how would one test it correctly with gtest? I am mainly going for coverage and testing branches more than values. As such I was expecting to do something like this:
EXPECT_CALL(adapter, IsFilled(0)).Times(zeroCalls).WillOnce(IndexZeroResults);
EXPECT_CALL(adapter, IsFilled(1)).Times(oneCalls).WillOnce(IndexOneResults);
EXPECT_CALL(adapter, IsFilled(_)).Times(otherCalls).WillOnce(IndexOtherResults);
I need the 0/1 calls separated as then I can test all branches, however, the "_" would duplicate the 0/1 calls as it tests with random values. Is it possible to exclude it?
TL;DR - swap the order of EXPECT_CALLs:
EXPECT_CALL(adapter, IsFilled(_)).Times(otherCalls).WillOnce(IndexOtherResults);
EXPECT_CALL(adapter, IsFilled(1)).Times(oneCalls).WillOnce(IndexOneResults);
EXPECT_CALL(adapter, IsFilled(0)).Times(zeroCalls).WillOnce(IndexZeroResults);
This works because of GoogleMock rules for ordering EXCEPT_CALLs. Expectations are always considered in reverse order than they were declared (so last declared expectation is verified first). It is like that to allow you to create general expectations in test fixture and specific expectations in test body.

Find first over several streams of different collection Types

public class ImmutableCrazySquares {
private final List<Square> xraySquare;
private final Map<String, Set<Square>> yankeSquare
private final Map<String, Set<Square>> zuloSquare;
.
.
.
#VisibleForTesting
private boolean exists(String squareId) {
boolean matches = yankeSquare.values().stream().anyMatch(squares ->
squares.stream().anyMatch(square -> square.getId().equals(squareId)));
if (!matches) {
matches = xraySquare.stream()
.anyMatch(square -> square.getId().equals(squareId));
}
if (!matches) {
matches = zuloSquare.values().stream().anyMatch(squares ->
squares.stream().anyMatch(square -> square.getId().equals(squareId)));
}
return matches;
}
}
The above class has a dozen methods but right now I just want to focus on this exists methods.
In essence I want to look at the 3 collections xraySquare, yankeSquare, zuloSquare and if the id I sent is in any of them I want to return true.
Sadly the Key on both the Maps are not the Id and therefore cannot be used for this action. To get the Id I need to drill in the values and call getId(). Since this is a method for tests I do not want to pollute the class with an adicional collection with all ids that exist.
Is there an easy way to concurrently look at all 3 collections and stop as soon as 1 finds the result?
concurrently might turn out to be slower than sequentially, so your code IMO is just fine. It can be slightly improved:
return
yankeSquare.values()
.stream()
.flatMap(Set::stream)
.map(Square::getId)
.anyMatch(Predicate.isEqual(squareId)) ||
xraySquare.stream()
.map(Square::getId)
.anyMatch(Predicate.isEqual(squareId)) ||
zuluSquare.values()
.stream()
.flatMap(Set::stream)
.map(Square::getId)
.anyMatch(Predicate.isEqual(squareId))
Or even simpler, but not as lazy as you have it in your code:
Stream.concat(xraySquare.stream(),
Stream.of(yankeSquare, zuloSquare)
.flatMap(map -> map.values().stream().flatMap(Set::stream))
.map(Square::getId)
.anyMatch(Predicate.isEqual(squareId))
)
Basically it flattens all your Collections to Stream<String> and check against that with anyMatch

NUnit 3.X - How to pass dynamic parameters into a TestCase or TestCaseSource?

CGrunddaten m_grdDaten;
[SetUp]
public void Init()
{
m_grdDaten = new CGrunddaten();
m_grdDaten.m_cwdGeoH.m_dW = 325.0;
m_grdDaten.m_cwd_tl.m_dW = 15;
}
[Test]
public void TestMethod()
{
m_grdDaten.RechGrdDaten();
Assert.That(m_grdDaten.m_cwd_pl.m_dW, Is.EqualTo(93344).Within(.1),"Außenluftdruck");
Assert.That(m_grdDaten.m_cwd_pl_neb.m_dW, Is.EqualTo(93147.3).Within(.1), "Außenluftdruck Nebenluftberechnung");
Assert.That(m_grdDaten.m_cwd_pl_pmax.m_dW, Is.EqualTo(92928.2).Within(.1), "Außenluftdruck max. zul. Unterdruck");
Assert.That(m_grdDaten.m_cwdRho_l.m_dW, Is.EqualTo(1.124).Within(.001), "Dichte Außenluft");
Assert.That(m_grdDaten.m_cwdRho_l_neb.m_dW, Is.EqualTo(1.184).Within(.001), "Dichte Außenluft Nebenluftberechnung");
Assert.That(m_grdDaten.m_cwdRho_l_pmax.m_dW, Is.EqualTo(1.249).Within(.001), "Dichte Außenluft max. zul. Unterdruck");
}
Is there a way to get this in a TestCase or TestCaseSource, so that I have only one Assert-line ?
I'm talking about this:
m_grdDaten.m_cwd_pl.m_dW, 93344
m_grdDaten.m_cwd_pl_neb.m_dW, 93147.3
m_grdDaten.m_cwd_pl_pmax.m_dW, 92928.2
....
I know that TestCase and TestCaseSource are static.... but is there another way?
The best way to do this test would be using the not-yet-implemented multiple asserts feature, so that all the asserts would run even if some failed.
Since that's not available yet, I can understand your wanting to make this into multiple tests, where each gets reported separately. Using test cases makes this possible, of course, even though this is really logically just one test.
The fact that a test case source method must be static doesn't prevent it from creating an instance of your CGrunddaten class. The tests themselves are all just comparing two doubles for equality and don't need to know anything about that class.
You could write something like this:
private static IEnumerable<TestCaseData> GrundDatenDaten
{
var gd = new CGrunddaten();
gd.m_cwdGeoH.m_dW = 325.0;
gd.m_cwd_tl.m_dW = 15;
gd.RechGrdDaten();
yield return new TestCaseData(gd.m_cwd_pl.m_dW, 93344, .1, "Außenluftdruck");
// und so weiter
}
[TestCaseSource("GrundDatenDaten")]
public void testMethod(object actual, object expected, object tolerance, string label)
{
Assert.That(actual, Is.EqualTo(expected).Within(tolerance), label);
}
However, I don't like that very much as it hides the true function of the test in the data source. I think your original formulation is the best way to do it for now and leaves you with the ability to include the code in an Assert.Multiple block once that feature is implemented.

Looking for testable design in described case

I have a system, which gets lists of objects from external system in some ABC-format, converts it to internal representation and passes to external service:
class ABCService() {
public ABCService(ExtService extService) {
this.extService = extService;
}
public void do(ABCData [] abcObjs) throws NoDataException {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
}
extService.do(objs);
}
}
}
When it comes to testing ABCService, we can test two things:
If no data is passed to "do", service throws an exception;
If some data is passed to "do", service should call extService and pass exactly the same number of objects, it has received from test caller.
But, though Parser factory is also tested, there is no guarantee, that output "objs" array is somehow connected to input abcObjs (e.g. method has created list with the predefined length, but method "forgets" to populate the list).
I my opinion those two test cases don't fully cover method's workflow leaving some of it dangerously untested.
How to modify ABCService design to increase it's testability?
The major testing difficulty in this code is that you have two collaborators and one of them is static.
If you can convert your Parser to a non-static (or perhaps wrap it in a non-static) and inject that as you do the extService, you could test that the parser is called the right number of times with the right arguments. Stubbing in the return values from the parser, you could also verify that your extService is called with the appropriately transformed objects instead of just the correct number of objects.
The problem you encountered is trying to handle two tasks in one function. The function do can be logically separated into two different member functions, so that you can use unittest for each of them.
By using refactoring, you can extract out the parsing and populating logic into another member function.
class ABCService() {
public void do(ABCData [] abcObjs) throws NoDataException {
extService.do(populateList(abcObjs));
}
List<Data> popuateList(ABCData[] abcObjs) {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
return objs;
}
}
}
while your current unittest can still remain for the "do" function, and additionally, you can add a unittest case for "populateList" function to ensure it generate correct data list

Should I add features in a class just to make it testable?

I am still trying to get the hang of unit testing, I have a simple question. Today I wanted to write a test for a very simple function. This function was doing just this:
void OnSomething()
{
increment++;
if (increment == 20)
SaveIt();
}
I said, this function could be testable. I could write a test that calls it 20 times and then verifies that SaveIt has been called.
Then my doubt arose. How can I test that SaveIt has been called? My first answer was to add a boolean, but then I thought: is it correct to add class features just to make it testable?
Please advise. Thank you.
I would suggest having SaveIt return a success or failure result, this just makes it easier to test overall. You could do something as simple as having it return a bool, or you could create a generic result class that contains the ability to set messages as well, if you ever need to report whether it passed or failed.
A simple example example
public class Result
{
public bool IsSuccess;
public List<string> Messages;
}
In the unit test you're trying to test only the OnSomething behavior though -- what happens inside "SaveIt" should not be tested. So ideally you'd want SaveIt() to occur in another class so you can mock its response.
I use Moq for this purpose. Moq is free, you can get it here: http://code.google.com/p/moq/
my method would then become
Result OnSomething()
{
Result result=null;
increment++;
if(increment == 20)
{
result = saver.SaveIt();
}
return result;
}
Your class constructor would take an object that implements ISaver interface (defining SaveIt() method) (ideally injected by a DI framework but you could generate it manually if you had to).
Now in your unit test you would create a mock version of ISaver and tell it what to return when it gets called:
Mock<ISaver> mock = new Mock<ISaver>();
mock.Setup(x=> x.SaveIt()).Returns(new Result{IsSuccess=true});
You'd instantiate your class passing mock.Object in the constructor ISaver parameter.
ex.
MyClass myClass = new MyClass(mock.Object);
//(assuming it didn't have other parameters)
Then, you could Assert whether result is null or not -- if it never got called, it would be null because the setup you did above would never trigger.
(in nunit)
Result result = myClass.OnSomething();
Assert.IsNotNull(result);
If you really didn't want OnSomething() to return a result, or it couldn't because it's an event, then I would have OnSomething() call a method to do the work for you:
void OnSomething()
{
Result result = DoTheWork();
}
Result DoTheWork()
{
Result result=null;
increment++;
if(increment == 20)
{
result = saver.SaveIt();
}
return result;
}
And then run your unit test on DoTheWork() instead of OnSomething().
Definitely not! Production code should not depend on tests at all, but the tests should verify the correct behaviour of the actual code. This can be achieved by several methods, such as IOC, and using mocks. You can take a look at some existing frameworks which simplify your life a lot:
http://code.google.com/p/mockito/
http://code.google.com/p/jmockit/
http://www.easymock.org/