//****************************************************************************//
//****************** More Unit Tests - November 3rd, 2017 *******************//
//**************************************************************************//

- So, because of how far we've been pushed back by the hurricane, I'm making M11 OPTIONAL - you can do it individually for EXTRA CREDIT
    - M12, the system evaluation, will still be required for everyone, though
---------------------------------------------------------------------------

- So, the main JUnit part is the "assertion"; here's a list of the most important ones:
    - Assert.assertTrue(msg, condition)
    - Assert.assertEquals(msg, expected, actual)    //uses .equals, value equivalence
    - Assert.assertNull(msg, variable)
    - Assert.assertSame(msg, v1, v2)            //uses ==, checks if addresses are same
    - Assert.assertNotSame(msg, v1, v2)
    - Assert.fail(msg)
        - "If your code should never do something, this will always throw an exception when it's reached"

- Practically, where do we put our tests in Android stduio?
    - Let's say in our java/src/main/model folder (or wherever), we have a "Stack" class that we want to write tests for
    - Now, in the "test" folder Android provides, create a new class called "StackTest" (could be called anything, but <classname>Test is a common convention), and add in an "@Before" method to set up any variables we'll need for our tests (usually called "setUp()")
        - Then, for each test method (@Test), we write our test methods with assert statements to verify that everything's working
            - "The old philosophy of testing was to create 1 test method per method that we were testing - so, we'd have a "testPop" method, then have a bunch of assert statements for all the different inputs we wanted to test for pop()"
            - "The more modern way of doing things is to create one method PER condition that we're pushing - e.g. instead of a single 'testStack' method, we'd have a bunch of methods like 'testEmptyStackPop', 'testPopAfterPush', etc. - ideally, each with only a single assert statement testing a single condition"
    - Then, with all our tests written, we just run that class alone ("StackTest") and see if our tests pass or fail
        - "Also, a quick tip - write as many of your tests as you can for your non-Android classes; that way, you don't have to wait for the whole emulator and everything to launch before you run your tests, you can just run the tests right away. It'll save you time"
            - "...this is also a good way to verify that you're keeping your business logic separate from the Android display stuff"
            - Tests are also shorter, since we don't have to fetch all the Android UI stuff, etc.

- Now, sometimes we'll HAVE to run tests on our actual Android classes, which requires us to set up an "ActivityTestRule" variable to hook up our Activity to our test
    - Can also use an API Google provides called "Espresso" - see Google's Android documentation for "Testing your App" for a good introduction
    - This lets us simulate input into textboxes, clicks on parts of the screen, test Android-specific classes (e.g. UI widgets), etc.

- Now, sometimes you'll hear about people "mocking up" the database, or running a test on some "mock" data
    - What they're talking about is this: let's say another team is in charge of designing the database for your application, so you have a meeting, decide on the interface you're going to use, and then write all your code...but the database people are behind schedule and haven't finished yet; so how are we going to test our database code?
        - Well, knowing the interface, we can use a "mock api" to setup a "fake" object with EXPECTATIONS - "if you recieve this input, do this" - to simulate our database, even though we don't have the actual database class
        - "This is a lot faster than trying to create a whole new fake implementation of the whole database; we can just specify how we would EXPECT the mock object to behave, instead of having the write the whole thing"

- One popular way of using tests is TDD - "Test Driven Development"
    - The basic idea of this is that BEFORE we write our actual code, we write the TESTS for that code and how we want it to behave
    - Then, we write all of our code for that class until it passes all of the tests
        - "Writing the tests FIRST forces you to think through how the class needs to behave and what it needs to do; it's not the only way to do that, but TDD is a popular way of doing things"

============================================

- Now, back to design principles, there's two kinds of change we were talking about: variation points (CURRENTLY required, know we need it to change) and evolution points (something we MIGHT need to handle later)

- Now, as far as this goes, there's 3 common kinds of developers:

    - Novices: Brittle designs that're easy to code at first, but are inflexible and hard to maintain

    - Intermediates: over-engineer things ("I'll use ALL these design patterns"), makes designs that are overly fancy and flexible and generalized in ways we probably won't ever need (easy to maintain, but hard to code at first)

    - Experts: They actually use their insight and experience to decide what can be brittle, and what NEEDS to be flexible (e.g. "The backend code for loading databases won't change, but the UI needs to be skinnable for future updates") - we get easy-to-code, hard-to-maintain stuff when we can get away with this, and we use hard-to-code, easy-to-maintain design when we need it
        - "This way, we're allowing for flexibility down the line, but not wasting time trying to overly-design everything"

- "Now, these GRASP principles are great points to follow when you're thinking about design, but they're pretty specific to our textbook; you won't hear to many interviewers asking you about GRASP."
- There are still quite a few other design principles we'll talk about: Law of demeter, Tell Don't Ask, CQS, SOLID, etc...but we'll start going over those on Monday