Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - https://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core_analytics;
18
 
1441 ariadna 19
use core_analytics\tests\mlbackend_helper_trait;
20
 
1 efrain 21
defined('MOODLE_INTERNAL') || die();
22
 
23
require_once(__DIR__ . '/fixtures/test_indicator_fullname.php');
24
require_once(__DIR__ . '/fixtures/test_target_shortname.php');
25
 
26
/**
27
 * Unit tests for the analytics stats.
28
 *
29
 * @package     core_analytics
30
 * @category    test
31
 * @copyright 2019 David Mudrák <david@moodle.com>
32
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
1441 ariadna 34
final class stats_test extends \advanced_testcase {
35
    use mlbackend_helper_trait;
1 efrain 36
 
37
    /**
38
     * Set up the test environment.
39
     */
40
    public function setUp(): void {
1441 ariadna 41
        parent::setUp();
1 efrain 42
 
43
        $this->setAdminUser();
44
    }
45
 
46
    /**
47
     * Test the {@link \core_analytics\stats::enabled_models()} implementation.
48
     */
11 efrain 49
    public function test_enabled_models(): void {
1 efrain 50
 
51
        $this->resetAfterTest(true);
52
 
53
        // By default, sites have {@link \core_course\analytics\target\no_teaching} and
54
        // {@link \core_user\analytics\target\upcoming_activities_due} enabled.
55
        $this->assertEquals(4, \core_analytics\stats::enabled_models());
56
 
57
        $model = \core_analytics\model::create(
58
            \core_analytics\manager::get_target('\core_course\analytics\target\course_dropout'),
59
            [
60
                \core_analytics\manager::get_indicator('\core\analytics\indicator\any_write_action'),
61
            ]
62
        );
63
 
64
        // Purely adding a new model does not make it included in the stats.
65
        $this->assertEquals(4, \core_analytics\stats::enabled_models());
66
 
67
        // New models must be enabled to have them counted.
68
        $model->enable('\core\analytics\time_splitting\quarters');
69
        $this->assertEquals(5, \core_analytics\stats::enabled_models());
70
    }
71
 
72
    /**
73
     * Test the {@link \core_analytics\stats::predictions()} implementation.
74
     */
11 efrain 75
    public function test_predictions(): void {
1441 ariadna 76
        if (!self::is_mlbackend_python_configured()) {
77
            $this->markTestSkipped('mlbackend_python is not configured.');
78
        }
1 efrain 79
 
80
        $this->resetAfterTest(true);
81
 
82
        $model = \core_analytics\model::create(
83
            \core_analytics\manager::get_target('test_target_shortname'),
84
            [
85
                \core_analytics\manager::get_indicator('test_indicator_fullname'),
86
            ]
87
        );
88
 
89
        $model->enable('\core\analytics\time_splitting\no_splitting');
90
 
91
        // Train the model.
92
        $this->getDataGenerator()->create_course(['shortname' => 'a', 'fullname' => 'a', 'visible' => 1]);
93
        $this->getDataGenerator()->create_course(['shortname' => 'b', 'fullname' => 'b', 'visible' => 1]);
94
        $model->train();
95
 
96
        // No predictions yet.
97
        $this->assertEquals(0, \core_analytics\stats::predictions());
98
 
99
        // Get one new prediction.
100
        $this->getDataGenerator()->create_course(['shortname' => 'aa', 'fullname' => 'aa', 'visible' => 0]);
101
        $result = $model->predict();
102
 
103
        $this->assertEquals(1, count($result->predictions));
104
        $this->assertEquals(1, \core_analytics\stats::predictions());
105
 
106
        // Nothing changes if there is no new prediction.
107
        $result = $model->predict();
108
        $this->assertFalse(isset($result->predictions));
109
        $this->assertEquals(1, \core_analytics\stats::predictions());
110
 
111
        // Get two more predictions, we have three in total now.
112
        $this->getDataGenerator()->create_course(['shortname' => 'bb', 'fullname' => 'bb', 'visible' => 0]);
113
        $this->getDataGenerator()->create_course(['shortname' => 'cc', 'fullname' => 'cc', 'visible' => 0]);
114
 
115
        $result = $model->predict();
116
        $this->assertEquals(2, count($result->predictions));
117
        $this->assertEquals(3, \core_analytics\stats::predictions());
118
    }
119
 
120
    /**
121
     * Test the {@link \core_analytics\stats::actions()} and {@link \core_analytics\stats::actions_not_useful()} implementation.
122
     */
11 efrain 123
    public function test_actions(): void {
1 efrain 124
        global $DB;
1441 ariadna 125
 
126
        if (!self::is_mlbackend_python_configured()) {
127
            $this->markTestSkipped('mlbackend_python is not configured.');
128
        }
129
 
1 efrain 130
        $this->resetAfterTest(true);
131
 
132
        $model = \core_analytics\model::create(
133
            \core_analytics\manager::get_target('test_target_shortname'),
134
            [
135
                \core_analytics\manager::get_indicator('test_indicator_fullname'),
136
            ]
137
        );
138
 
139
        $model->enable('\core\analytics\time_splitting\no_splitting');
140
 
141
        // Train the model.
142
        $this->getDataGenerator()->create_course(['shortname' => 'a', 'fullname' => 'a', 'visible' => 1]);
143
        $this->getDataGenerator()->create_course(['shortname' => 'b', 'fullname' => 'b', 'visible' => 1]);
144
        $model->train();
145
 
146
        // Generate two predictions.
147
        $this->getDataGenerator()->create_course(['shortname' => 'aa', 'fullname' => 'aa', 'visible' => 0]);
148
        $this->getDataGenerator()->create_course(['shortname' => 'bb', 'fullname' => 'bb', 'visible' => 0]);
149
        $model->predict();
150
 
151
        list($p1, $p2) = array_values($DB->get_records('analytics_predictions'));
152
 
153
        $p1 = new \core_analytics\prediction($p1, []);
154
        $p2 = new \core_analytics\prediction($p2, []);
155
 
156
        // No actions executed at the start.
157
        $this->assertEquals(0, \core_analytics\stats::actions());
158
        $this->assertEquals(0, \core_analytics\stats::actions_not_useful());
159
 
160
        // The user has acknowledged the first prediction.
161
        $p1->action_executed(\core_analytics\prediction::ACTION_FIXED, $model->get_target());
162
        $this->assertEquals(1, \core_analytics\stats::actions());
163
        $this->assertEquals(0, \core_analytics\stats::actions_not_useful());
164
 
165
        // The user has marked the other prediction as not useful.
166
        $p2->action_executed(\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED, $model->get_target());
167
        $this->assertEquals(2, \core_analytics\stats::actions());
168
        $this->assertEquals(1, \core_analytics\stats::actions_not_useful());
169
    }
170
}