How test SqlParameter for equality - unit-testing

Using NUnit and NMock2 I was not able to compare what I thought were the same SqlParameters:
SqlParameter param1 = new SqlParameter("#Id", 1);
SqlParameter param2 = new SqlParameter("#Id", 1);
Assert.IsTrue(param1.Equals(param2)); // This failed
I stumbled across this problem, when trying to test an execution of a method using NMock2
[Test]
public void UpdateComments()
{
const int arbitraryId = 1;
Comment comment = new Comment();
SqlParameter idParam = new SqlParameter("#ChangeId", arbitraryId);
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", idParam);
changeDao.UpdateComment(arbitraryId, comment);
mocks.VerifyAllExpectationsHaveBeenMet();
}
I received this error:
NMock2.Internal.ExpectationException: unexpected invocation of sqlDao.ExecuteNonQuery("usp_Update_Comment", )
Expected:
1 time: sqlDao.ExecuteNonQuery(equal to "usp_Update_Comment", equal to <#ChangeId>) [called 0 times]
Questions:
How do you test with NMock2 when you
expected Parameter is SqlParameter?
How do you compare equality of two SqlParameters?

Because .Equals() is using the default implementation of Equals as far as I know (which means that a SqlParameter will only "equal" another SqlParameter if they are the same object), you will need to directly interrogate the properties of the parameter to ensure the correct data is being passed.
The Has.Property call within .With allows you to check the properties of a parameter without requiring that a parameter equals some other value. Try the following:
Expect.Once.On(mockSqlDao).Method("ExecuteNonQuery")
.With("usp_Update_Comment", Has.Property("ParameterName").EqualTo("#Id") &
Has.Property("Value").EqualTo(1));

Related

Assert mock call with argument assigned in where block in Spock

I have a method that among others generates an identifier, sends it to some external dependency and returns it. I want to have a unit test that tests if the same value that was sent there is returned.
Let's say that the test and the code look like this:
def "test"() {
given:
def testMock = Mock(TestMock)
and:
def x
when:
def testClass = new TestClass()
x = testClass.callMethod(testMock)
then:
1 * testMock.method(x)
}
static interface TestMock {
void method(double x)
}
static class TestClass {
double callMethod(TestMock mock) {
double x = Math.random()
mock.method(x)
return x
}
}
The code works correct, however the test fails with a message:
One or more arguments(s) didn't match:
0: argument == expected
| | |
| | null
| false
0.5757686318956925
So it looks like the mock check in then is done before the value is assigned in when block.
Is there a way to make Spock assign this value before he checks the mock call? Or can I do this check in a different way?
The only idea I have is to inject an id-generator to the method (or actually to the class) and stub it in the test, but it would complicate the code and I would like to avoid it.
I fixed code example according to kriegaex comment.
Fixing the sample code
Before we start, there are two problems with your sample code:
1 * testMock(x) should be 1 * testMock.method(x)
callMethod should return double, not int, because otherwise the result would always be 0 (a double between 0 and 1 would always yield 0 when converted to an integer).
Please, next time make sure that your sample code not only compiles but also does the expected thing. Sample code is only helpful if it does not have extra bugs, which a person trying to help you needs to fix first before being able to focus on the actual problem later on.
The problem at hand
As you already noticed, interactions, even though lexically defined in a then: block, are transformed in such a way by Spock's compiler AST transformations, that they are registered on the mock when the mock is initialised. That is necessary because the mock must be ready before calling any methods in the when: block. Trying to directly use a result only known later while already executing the when: block, will cause the problem you described. What was first, chicken or egg? In this case, you cannot specify a method argument constraint, using the future result of another method calling the mock method in the constraint.
The workaround
A possible workaround is to stub the method and capture the argument in the closure calculating the stub result, e.g. >> { args -> arg = args[0]; return "stubbed" }. Of course, the return keyword is redundant in the last statement of a closure or method in Groovy. In your case, the method is even void, so you do not need to return anything at all in that case.
An example
I adapted your sample code, renaming classes, methods and variables to more clearly describe which is what and what is happening:
package de.scrum_master.stackoverflow.q72029050
import spock.lang.Specification
class InteractionOnCallResultTest extends Specification {
def "dependency method is called with the expected argument"() {
given:
def dependency = Mock(Dependency)
def randomNumber
def dependencyMethodArg
when:
randomNumber = new UnderTest().getRandomNumber(dependency)
then:
1 * dependency.dependencyMethod(_) >> { args -> dependencyMethodArg = args[0] }
dependencyMethodArg == randomNumber
}
}
interface Dependency {
void dependencyMethod(double x)
}
class UnderTest {
double getRandomNumber(Dependency dependency) {
double randomNumber = Math.random()
dependency.dependencyMethod(randomNumber)
return randomNumber
}
}
Try it in the Groovy Web Console.

Spock - How to work with repeated interactions

For few test cases I'm trying to follow a DRY principle, where only the interactions are different with same test case conditions. I'm not able to find a way to implement multiple methods in the interaction { } block.
As mentioned in http://spockframework.org/spock/docs/1.3/interaction_based_testing.html#_explicit_interaction_blocks, I'm using interaction { } in the then: block like below:
Java Code:
// legacy code (still running on EJB 1.0 framework, and no dependency injection involved)
// can't alter java code base
public voidGetData() {
DataService ds = new DataService();
ds = ds.findByOffset(5);
Long len = ds.getOffset() // happy path scenario; missing a null check
// other code
}
// other varieties of same code:
public voidGetData2() {
ItemEJB tmpItem = new ItemEJB();
ItemEJB item = tmpItem.findByOffset(5);
if(null != item) {
Long len = item.getOffset();
// other code
}
}
public voidGetData3() {
ItemEJB item = new ItemEJB().findByOffset(5);
if(null != item) {
Long len = item.getOffset();
// other code
}
}
Spock Test:
def "test scene1"() {
given: "a task"
// other code ommitted
DataService mockObj = Mock(DataService)
when: "take action"
// code omitted
then: "action response"
interaction {
verifyNoDataScenario() // How to add verifyErrorScenario() interaction to the list?
}
}
private verifyDataScenario() {
1 * mockObj.findByOffset(5) >> mockObj // the findByOffset() returns an object, so mapped to same mock instance
1 * mockObj.getOffset() >> 200
}
private verifyErrorScenario() {
1 * mockObj.findByOffset(5) >> null // the findByOffset() returns null
0 * mockObj.getOffset() >> 200 // this won't be executed, and should ie expected to throw NPE
}
The interaction closure doesn't accept more than one method call. I'm not sure if it's design limitation. I believe more can be done in the closure than just mentioning the method name. I also tried interpolating the mockObj as a variable and use data pipe / data table, but since it's referring the same mock instance, it's not working. I'll post that as a separate question.
I ended up repeating the test case twice just to invoke different interaction methods. Down the line I see more scenarios, and wanted to avoid copy & paste approach. Appreciate any pointers to achieve this.
Update:
Modified shared java code as the earlier DataService name was confusing.
As there's no DI involved, and I didn't find a way to mock method variables, so I mock them using PowerMockito, e.g. PowerMockito.whenNew(DataService.class).withNoArguments().thenReturn(mockObj)
Your application code looks very strange. Is the programming style in your legacy application really that bad? First a DataService object is created with a no-arguments constructor, just to be overwritten in the next step by calling a method on that instance which again returns a DataService object. What kind of programmer creates code like that? Or did you just make up some pseudo code which does not have much in common with your real application? Please explain.
As for your test code, it also does not make sense because you instantiate DataService mockObj as a local variable in your feature method (test method), which means that in your helper method mockObj cannot be accessed. So either you need to pass the object as a parameter to the helper methods or you need to make it a field in your test class.
Last, but not least, your local mock object is never injected into the class under test because, as I said in the first paragraph, the DataService object in getData() is also a local variable. Unless your application code is compeletely fake, there is no way to inject the mock because getData() does not have any method parameter and the DataService object is not a field which could be set via setter method or constructor. Thus, you can create as many mocks as you want, the application will never have any knowledge of them. So your stubbing findByOffset(long offset) (why don't you show the code of that method?) has no effect whatsoever.
Bottom line: Please provide an example reflecting the structure of your real code, both application and test code. The snippets you provide do not make any sense, unfortunately. I am trying to help, but like this I cannot.
Update:
In my comments I mentioned refactoring your legacy code for testability by adding a constructor, setter method or an overloaded getData method with an additional parameter. Here is an example of what I mean:
Dummy helper class:
package de.scrum_master.stackoverflow.q58470315;
public class DataService {
private long offset;
public DataService(long offset) {
this.offset = offset;
}
public DataService() {}
public DataService findByOffset(long offset) {
return new DataService(offset);
}
public long getOffset() {
return offset;
}
#Override
public String toString() {
return "DataService{" +
"offset=" + offset +
'}';
}
}
Subject under test:
Let me add a private DataService member with a setter in order to make the object injectable. I am also adding a check if the ds member has been injected or not. If not, the code will behave like before in production and create a new object by itself.
package de.scrum_master.stackoverflow.q58470315;
public class ToBeTestedWithInteractions {
private DataService ds;
public void setDataService(DataService ds) {
this.ds = ds;
}
// legacy code; can't alter
public void getData() {
if (ds == null)
ds = new DataService();
ds = ds.findByOffset(5);
Long len = ds.getOffset();
}
}
Spock test:
Now let us test both the normal and the error scenario. Actually I think you should break it down into two smaller feature methods, but as you seem to wish to test everything (IMO too much) in one method, you can also do that via two distinct pairs of when-then blocks. You do not need to explicitly declare any interaction blocks in order to do so.
package de.scrum_master.stackoverflow.q58470315
import spock.lang.Specification
class RepeatedInteractionsTest extends Specification {
def "test scene1"() {
given: "subject under test with injected mock"
ToBeTestedWithInteractions subjectUnderTest = new ToBeTestedWithInteractions()
DataService dataService = Mock()
subjectUnderTest.dataService = dataService
when: "getting data"
subjectUnderTest.getData()
then: "no error, normal return values"
noExceptionThrown()
1 * dataService.findByOffset(5) >> dataService
1 * dataService.getOffset() >> 200
when: "getting data"
subjectUnderTest.getData()
then: "NPE, only first method called"
thrown NullPointerException
1 * dataService.findByOffset(5) >> null
0 * dataService.getOffset()
}
}
Please also note that testing for exceptions thrown or not thrown adds value to the test, the interaction testing just checks internal legacy code behaviour, which has little to no value.

How to call mock method instead of real method in mockito/Junit

I want to call ClassA.mockMethod() whenever objOfClassB.realMethod() method is invoked.
public class ClassA{
public static int mockMethod(String url, MySql sql){
int res=0
// do work
return ;
}
}
Definition of executeUpdate1()
class Veps{
protected synchronized int realMethod(String url, MySql sql){
----
-----
}
}
public class VepsTest {
public void setUp() throws Exception {
veps = mock(Veps.class);
when(objOfClassA.realMethod(any(String.class), any())).thenReturn(objOfClassB.mockMethod(any(String.class),any()));
}
}
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 4 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
the mockito reports the errors clearly:
Invalid use of argument matchers! 2 matchers expected, 4 recorded.
you shouldn't using Matchers in any then* clause. your problem can be fixed as:
when(veps.executeQuery1(any(String.class), any(MySql.class)))
.thenReturn(DBConnection.mockExecuteQuery("??","??"));
when(veps.executeUpdate1(any(String.class), any()))
.thenReturn(DBConnection.mockExecuteUpdate("??","??"));
but another problem appears: why did you need query the result from the database? you can simply take a constant value to fake the result:
when(veps.executeQuery1(any(String.class), any(MySql.class)))
.thenReturn(1);
// ^--- replace the constant 1 with yours
when(veps.executeUpdate1(any(String.class), any()))
.thenReturn(1);
// ^--- replace the constant 1 with yours
you need to see mockito documentation as further before using it in your test.

RSpec: expect array of hashes in class_double recieve

I want to test with RSpec a function my_test. The function calls another class's class method MyHelper.func in rails 4.
I used mock to illustrate func in class MyHelper, and I want to match the argument that func receives with some const values.
I used
expect(<double>).to receive(func).with(arguments)
But one of the const arguments is a hash with more than 2 items. When I test my
function, RSpec throws an error:
received :func with unexpected arguments.
expected: [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}]
got: [{"2"=>33.33},{"1"=>33.33},{"3"=>33.33}]
Is there a way to match between the two arrays?
The code:
my_hash = [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}]
notifier = class_double("MyHelper").
as_stubbed_const(:transfer_nested_constant => true)
expect(notifier).to receive(:func).with(my_hash)
This is a bit tricky since you are comparing two things that are not equal when using ==
let(:expected) { [{"1"=>33.33},{"2"=>33.33},{"3"=>33.33}] }
let(:actual) { [{"2"=>33.33},{"1"=>33.33},{"3"=>33.33}] }
expect(actual).to eq(expected) # fails
However, you can define a custom matcher and use it to compare the arguments:
RSpec::Matchers.define :sorted_array_match do |expected|
match do |actual|
expected_hash = expected.inject({}) {|m,(k,v)| m.merge!(k=>v)}
actual_hash = actual.inject({}) {|m,(k,v)| m.merge!(k=>v)}
actual_hash == expected_hash
end
end
it "should work" do
expect(notifier).to receive(:func).with(sorted_array_match(expected))
notifier.func(actual)
end
Note that this converts the array argument into a hash, so it assumes the arguments are arrays containing hashes with different keys. You might need to alter it to fit the actual data.
More info in the RSpec docs.

Trouble using Autofixture's CreateProxy to use Likeness, SemanticComparison features

In an earlier question I asked about Autofixture's CreateProxy method, a potential bug was identified.
I don't think this failing test is as a result of that, but rather my continued confusion about how the Likeness.Without(...).CreateProxy() syntax works. Consider the following failing test in which I make the original test ever so slightly more complex by creating a new instance of the object, considering its creation to be the SUT:
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass,
Strings = template.Brass};
// intent -> specify that .Brass should not be considered in comparison
var likeness = template.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // Ignore .Brass property
// per [https://stackoverflow.com/a/15476108/533958] explicity assign
// properties to likeness
likeness.Strings = template.Strings;
likeness.Brass = "foo"; // should be ignored
// assert: intent -> check equality between created Band & template Band
// to include all members not excluded in likeness definition
likeness.Should().Be(createdBand); // Fails
likeness.ShouldBeEquivalentTo(createdBand); // Fails
Assert.True(likeness.Equals(createdBand)); // Fails
}
Here's the Band:
public class Band
{
public string Strings { get; set; }
public string Brass { get; set; }
}
My earlier question wasn't sufficiently complex to help me understand what the Source of the Likeness should be in general.
Should the source be the output of the SUT, in which case it would be compared to the template instance created by AutoFixture?
Or should the source be the template instance created by AutoFixture, in which case it would be compared to the output of the SUT?
EDIT: Corrected an error in the test
I realized that I had incorrectly assigned the template.Brass property to both the Brass and the Strings property of the new Band instance. The updated test reflects the correction with var createdBand = new Band {Brass = template.Brass, Strings = template.Strings} and all six assertions pass now.
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass, Strings = template.Strings};
// likeness of created
var createdLikeness = createdBand.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // .Brass should not be considered in comparison
// https://stackoverflow.com/a/15476108/533958 (explicity assign properties to likeness)
createdLikeness.Strings = createdBand.Strings;
createdLikeness.Brass = "foo"; // should be ignored
// likeness of template
var templateLikeness = template.AsSource().OfLikeness<Band>()
.Without(x => x.Brass)
.CreateProxy();
templateLikeness.Strings = template.Strings;
templateLikeness.Brass = "foo";
// assert: intent -> compare created Band to template Band
createdLikeness.Should().Be(template);
createdLikeness.ShouldBeEquivalentTo(template);
Assert.True(createdLikeness.Equals(template));
templateLikeness.Should().Be(createdBand);
templateLikeness.ShouldBeEquivalentTo(createdBand);
Assert.True(templateLikeness.Equals(createdBand));
}
What you mean is:
likeness.Should().BeAssignableTo<Band>(); // Returns true.
In the example provided, the proxy generated from Likeness is a type deriving from Band, overriding Equals using the Semantic Comparison algorithm.
Using Reflection that is:
createdBand.GetType().IsAssignableFrom(likeness.GetType()) // Returns true.
Update:
The createBand and template instances are not affected by the CreateProxy method. Why they should?
With Likeness CreateProxy you basically create a Custom Equality Assertion that allows you to do:
Assert.True(likeness.Equals(createdBand)); // Passed.
Without it, the original Equality Assertion would fail:
Assert.True(template.Equals(createdBand)); // Failed.
However, the following will also fail:
Assert.True(likeness.Equals(template));
It fails because the Strings value is the one from the createdBand instance.
This behavior is expected, and you can verify it using Likeness directly:
createdBand.AsSource().OfLikeness<Band>()
.Without(x => x.Brass).ShouldEqual(template);
Output:
The provided value `Band` did not match the expected value `Band`. The following members did not match:
- Strings.