I agree that using Constructor or Property Injection would make my life easier. Unfortunatley our production app has already had it's IoC architecture decided -- I'm happy enough to hopefully bring BDD to the party.
So I was thinking after reading more about AMC implementation and I found that the concept of providing/injecting an object of your choice in addition to just providing a type to my service locator would allow me to create a mock or a stub depending on what I need for the test and the locator would use that when the SUT asked for it. I also made the AMC use constructor injection for the mock repository -- the previous implementation ended up having two, which sounds like a recipe for disaster. So I added that feature to our AMC and it solved the two specific issues I presented! I provided a stub for the IEnterNumber implementation of the first test, and I provided a mock for the IEnterDigit in the second. Of course I ran into a third issue though: I had some code that needed two instances of the same interface, but since I had provided a stub for the first need the code only had 1 reference and it didn't work. Luckily all I had to do was provide a second stub instance AFTER the first one was referenced by the code. It worked perfectly after that. All in all, I think this AMC is cleaner than it was and I have more control over what I want to do. I think I might run into trouble later if I have some code that needs two instances of the same interface but I don't have the opportunity to step in and provide a second instance through the locator -- but I'll cross that bridge when I get there. Thanks Robin, Dan Lash On Nov 25, 4:24 pm, Robin Clowers <[EMAIL PROTECTED]> wrote: > The easier way I think would be to use dependency injection. If your > classes take all their dependencies in their constructors, you can > easily pass real implementations, mocks, or stubs at test time. You > could use an IoC container to facilitate the runtime construction of > objects, and likewise you could use an automocking container at test > time, but you don't need to. I am a big fan of StructureMap and it's > AMC, you can see the usage > here:http://codebetter.com/blogs/jeremy.miller/archive/2008/02/09/automock... > > On Nov 25, 6:31 am, Dan Lash <[EMAIL PROTECTED]> wrote: > > > > > I think the root of my problem is using a Service Locator pattern. I > > want my AMC to use stubs or mocks in different situations, but both > > tests are 'broken' because I'm using that particular IoC pattern. My > > code is asking the locator to give it an object that fulfills some > > interface -- and my test code is either going to want to put > > expectations on it OR not care about expectations but the object needs > > to work. > > > So I guess an easier way to ask the question is: what is a good way to > > test interaction when using a service locator pattern? > > > If the answer is AMC, how then can you control whether it's dolling > > out mocks or stubs? And if you can't how can you extract the mocks > > from your code to use in your test? > > > Thanks alot, > > > Dan Lash > > > On Nov 24, 3:45 pm, Dan Lash <[EMAIL PROTECTED]> wrote: > > > > I am working on a test project to prove out TDD/BDD before bringing it > > > to our next project. The test project is a simple 4-function > > > calculator and I've been able to get pretty far with state based > > > testing. Now I'm trying to do some interaction based testing and > > > running into some challenges. > > > > The calculator is using a Service Locator pattern to get the > > > implementations of the interfaces. Because of this, I thought that the > > > Auto Mocking Container (or the idea of it) would fit perfectly. But I > > > have two different situations where I need the AMC to work > > > differently. > > > > First, I am testing that when the Calculator is going to evaluate that > > > it interacts with the Math Engine properly. I have a test like this: > > > > [Test] > > > public void should_use_math_engine_to_add() > > > { > > > Expect.Call(_firstDigit.Digit).Return(4); > > > Expect.Call(_addOperation.Operation).Return > > > (Calculator.Core.Operations.Add); > > > Expect.Call(_secondDigit.Digit).Return(3); > > > Expect.Call(_math.Add(4, 3)).Return(7); > > > SetupResult.For(_addOperation2.Operation).Return > > > (Calculator.Core.Operations.Add); > > > > Mocks.ReplayAll(); > > > > _calculator.PerformAction(_firstDigit); > > > _calculator.PerformAction(_addOperation); > > > _calculator.PerformAction(_secondDigit); > > > _calculator.PerformAction(_addOperation2); > > > > Mocks.VerifyAll(); > > > > } > > > > The problem I have is that the Calculator implementation uses the > > > Locator to get an IEnterNumber to append the IEnterDigits before > > > working with the Math Engine, and since I'm using an AMC it get's a > > > mock. Since a mock doesn't store properties like stubs do I'm getting > > > exceptions the mock can't return a value unless you specify it. > > > > So one way I could fix that is by making my AMC return stubs instead. > > > That would allow the calculator to perform it's interaction with the > > > Math Engine and everything is good. I don't care how it uses > > > IEnterNumber internally, just that it interacts correctly with the > > > engine. > > > > BUT I have a different test that would have the opposite problem if I > > > changed it. That test verifys the interaction between my Presentation > > > Model and my Core. This is how it's set up: > > > > [Test] > > > public void should_perform_enter_digit_action_on_calculator() > > > { > > > _digitAction.Digit = 2; > > > _calculator.PerformAction(_digitAction); > > > > _digitAction.GetMockRepository().ReplayAll(); > > > > _model.AddDigit("2"); > > > > _digitAction.GetMockRepository().VerifyAll(); > > > > } > > > > The way that this test works is it gets the IEnterDigit from the AMC > > > so it can set up the expectations on the same object that the Model > > > will use. This test relys on the AMC to give a mock to the Model so it > > > can have proper expectations set on it. > > > > The main difference between the two is that in the first test I don't > > > care about the use of IEnterNumber because it's all internal -- but I > > > need it to work close to normal. The second test I care about > > > IEnterDigit because it's the method of communication between the Model > > > and the Core -- and I need to set expectations on it. > > > > So after all that explanation my question is: am I doing this right? > > > If both of the tests and my testing strategy seem right, how can I > > > mock and/or stub properly in both of them when they are using a > > > Service Locator pattern? > > > > I appreciate any advice on this. > > > > Dan Lash- Hide quoted text - > > - Show quoted text - --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Rhino.Mocks" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/RhinoMocks?hl=en -~----------~----~----~----~------~----~------~--~---
