locked
How to model objects that change state, and collections of them ?

    Dotaz

  • Hopefully this is just me not really understanding some very basic concepts ! :)

    I'm not quite understanding how we are supposed to model complex objects, to allow them to be tested properly.

    As a simple example, imagine I'm modelling a book and library system. I have a Library class, and a Book class. Book would have things like Title and Author. Library would contain a list of Books, and methods to add and remove books.

    I want to model an EditTitle  method on Book. I want to check that when I edit the Title, the Book object ends up with the new Title, plus everything else as it used to be. 

    My first attempt at getting something working was to return the edited Book from the EditTitle method so that it can be compared in the test. However, this is not allowed, as only certain kinds of objects are allowed as return values (or out parameters). I thought that having an Equals method on Book would allow Spec Explorer to use that to test for equality. 

    Next, I found I could make Book derive from CompoundValue, which would then be allowed as a parameter. However, I then can't change any data in the Book object (you can only set values during object creation). 

    This led me to wonder if the usual approach is to model using "normal" C# classes, but then have methods which extract the data (like generating DTOs perhaps) into structs or CompoundValue derived classes (or even check each individual primitive data item as a separate parameter), which would then be suitable for comparison in the generated tests.

    Alternatively, I see TypeBinding, which looks like it might also be something to do with this ?

    Or, is this where the State Checker pattern is supposed to be used ?

    Assuming I can get past this simple situation, I would then want to model the AddBook method on Library. To verify this is working, I'd simply want to return an entire list of Books from the model, and see that it matches the list returned from the SUT. I'm hoping that if I can check one item, then so long as I use one of the Modeling classes, like Sequence, to hold the Books, then a test should be able to compare them.

    Thanks again for your help :)

    13. února 2012 8:33

Odpovědi

  • As a general rule, you are not supposed to compare complex objects between model and implementation, because that would make them to tightly coupled. Think of an oracle that will give you sufficient confidence that the implementation is "doing the right thing", without inspecting its deep state. For example, after an insertion operation you could check whether the library has the right number of books, or if the set of all book titles matches the one expected by the model.

    Regarding the following paragraph:

    This led me to wonder if the usual approach is to model using "normal" C# classes, but then have methods which extract the data (like generating DTOs perhaps) into structs or CompoundValue derived classes (or even check each individual primitive data item as a separate parameter), which would then be suitable for comparison in the generated tests.

    The answer is yes. For most models, you create test adapters as an abstraction layer that keeps the model decoupled from the implementation details. You can read more about them here:

    http://blogs.msdn.com/b/specexplorer/archive/2009/11/23/connecting-your-tests-to-an-implementation.aspx 

    Best,

    Nico

    15. února 2012 18:25
    Moderátor

Všechny reakce

  •  

    Hi Guraaku,

    Some ideas to your question:

     "compound values" are immutable. But changing data on it can always be modeled by creating a complete new compound with the changed content. This is also what the derivatives of "compound values" like "sequence", "map" etc. do.

     With "TypeBinding" it is not possible to transfer the full object content to the test adapter. So comparing the complete content of an object must be done using structs, compound values and it's derivatives.

     To transfer this data to the test adapter you need an (in or out) argument of a rule-method. If you want to compare the full contents on every step the "state checker pattern" is your solution. If you are more relaxed you might need only one rule method call for comparison e.g. at the end of a test. You could also sequence the call with a scenario easily in cord.

     Storing structs in sequences, maps etc is possible. But we found a problem in Spec Explorer with nested structs inside a "map". Have not tried nested compound values so far.

    A related thread is also:

    http://social.msdn.microsoft.com/Forums/en-US/specexplorer/thread/0e5a6080-76fd-43c6-9ac7-c05bf30699b6

    Hope this helps

    • Upravený bububa 15. února 2012 9:39
    15. února 2012 9:38
  • As a general rule, you are not supposed to compare complex objects between model and implementation, because that would make them to tightly coupled. Think of an oracle that will give you sufficient confidence that the implementation is "doing the right thing", without inspecting its deep state. For example, after an insertion operation you could check whether the library has the right number of books, or if the set of all book titles matches the one expected by the model.

    Regarding the following paragraph:

    This led me to wonder if the usual approach is to model using "normal" C# classes, but then have methods which extract the data (like generating DTOs perhaps) into structs or CompoundValue derived classes (or even check each individual primitive data item as a separate parameter), which would then be suitable for comparison in the generated tests.

    The answer is yes. For most models, you create test adapters as an abstraction layer that keeps the model decoupled from the implementation details. You can read more about them here:

    http://blogs.msdn.com/b/specexplorer/archive/2009/11/23/connecting-your-tests-to-an-implementation.aspx 

    Best,

    Nico

    15. února 2012 18:25
    Moderátor
  • Hi Nico,

    Thanks for your reply, I think that does confirm to me how things should be being done.

    I see your point about having a model that will give you "sufficient confidence". I guess I'm thinking that I would like my model to be as "strong" as possible - yes, I could simply check whether the list has the right number of elements, etc, but then that won't rule out the possibility that some of those elements are being incorrectly modified somehow. In the simple example I gave, it's easy enough for the model to actually give the strongest correct answer, ie the list should look exactly like this list. Given the ease of building the model, I was hoping that the all the information in the model could be used to really give a more thorough check of the real system implementation. It's always a tradeoff as to how much work you want to put into testing/modelling against how much return you get - perhaps in more real life situations I won't find it as simple to build the model, so I may not be as tempted to want to do this level of checking. We'll see :)

    In terms of coupling the model and implementation, again, you make a good point. I agree, I don't want to couple them too tightly - but I do want to check that the correct information is able to be retrieved. So, for the Book, Title and Author is real business domain information that I need to ensure is correct. Yes, I don't care how that is stored, but I do want to know that it is correctly handled. So I guess the better thing to do is check that individual methods on the model, like GetTitle, and GetAuthor actually return the correct values.

    On reflection, I think the desire to have all that information in one object which could be checked for equality with the model was just to make the testing so much simpler - is this equal to that ? If I can't easily do it in one step, the test may become a lot more complex. I'll have a think about how I want to proceed with it. I think, if I keep the data that I'm comparing at the business domain level, tight coupling is not necessarily an issue - it's more just a grouping together of functions that are available individually anyway.

    I'll have a closer look at the State Checker pattern.

    Thanks again, I do appreciate you guys taking the time to help us newbies get to grips with Spec Explorer :)

    17. února 2012 5:43